1

I noticed this while try to create an flask-extension with pymodm. Consider a use case of pymodm.MongoModel.

Models.py (user defined medule)

#line 1
from pymodm import MongoModel, fields,connect

#line 2
connect("mongodb://localhost:27017/project_matrix")

#line 3
class Model(MongoModel):
    name = fields.CharField()

#line 4
Model({"name": "test"}).save()

The interesting thing about connect method of connections.py module is, it uses a module level variable called _CONNECTIONS to store all the connections. After importing connect to current name space in #line 2 We are adding a connection to _CONNECTIONS using connect method.

Then, in #line 4, we calls save method of TopLevelMongoModel class of models.py module which indirectly calls collections() of options.py. options.py imports the method _get_db of connections.py.

Summery:

Models.py imports connect method of connections.py to add a connection to module level variable. options.py imports _get_db of connections.py somehow managed to get a connection from _CONNECTIONS which is changed by Models.py.

What is the mechanism/concept behind this? are module level variables are global like in JavaScript or am I missing something?

Evhz
  • 8,852
  • 9
  • 51
  • 69
s1n7ax
  • 2,750
  • 6
  • 24
  • 53
  • I'm not sure what you're asking. There's only one instance of `_CONNECTIONS` which is used by two other modules; why is this surprising? – Daniel Roseman Apr 09 '17 at 18:25
  • well.. if a module is imported by two modules, those two modules should have two instances of `_CONNECTIONS` not one.. – s1n7ax Apr 09 '17 at 20:05
  • 1
    But why? What makes you think that? If you assign an object to two names, you still only have one object, not two. – Daniel Roseman Apr 09 '17 at 20:10
  • Is the underlying issue: why/how does Flask follow the convention of setting extension configs at the app level? – brennan Apr 10 '17 at 14:49

1 Answers1

0

if a module is imported by two modules, those two modules should have two instances of _CONNECTIONS not one.

This is not so.

Your imports work that way because that's the way imports work. The import statement does not create a new module each time it is invoked. If the module has been previously imported, subsequent imports simply bind to the original module.

Consider these three files:

main.py

import a
import b
print(f"main, imports complete, a.x={a.x}, b.a.x={b.a.x}")
a.x = 7
print(f"modified a.x, a.x={a.x}, b.a.x={b.a.x}")

a.py

x = 3
print(f"Inside a, x={x}")

b.py

import a
print(f"Inside b, a.x={a.x}")

and this python3.6 session:

$ python3.6 main.py
Inside a, x=3
Inside b, a.x=3
main, imports complete, a.x=3, b.a.x=3
modified a.x, a.x=7, b.a.x=7

Notice two important things:

  • The Inside a line is only printed once. Even though a is imported from both main and b, Inside a is only printed the first time a is imported. This is important: the code in a is only ever executed once.

  • The modification to a.x affects both a.x and b.a.x. This is also important. There is only one a module, and therefore only one a module namespace. Anyone who imported a will see the same namespace with the same names and the same objects.

Robᵩ
  • 163,533
  • 20
  • 239
  • 308