Reputation: 9039
Can someone explain the logic behind how this works with the Python interpreter? Is this behavior only thread local? Why does the assignment in the first module import persist after the second module import? I just had a long debugging session that came down to this.
external_library.py
def the_best():
print "The best!"
modify_external_library.py
import external_library
def the_best_2():
print "The best 2!"
external_library.the_best = the_best_2
main.py
import modify_external_library
import external_library
external_library.the_best()
Test:
$ python main.py
The best 2!
Upvotes: 3
Views: 2416
Reputation: 2491
Modules are instances of new-style classes. When you modify the attributes of a module (the function in this case), you are modifying the module instance. When you try to import it again (with import external_library
), you're just getting the same module object already referenced inside of modify_external_library.py
.
Edit: Of course, trying to import the same module again does not really work (as Alex Martelli points out). Once loaded, modules are not re-initialized unless done so explicitly with reload
.
Upvotes: 2
Reputation: 55469
As Alex indicated you need to reload external_library
, simply importing it will do nothing if it's already been imported. You can check that by putting print
statements into your external_library
and modify_external_library
modules.
import modify_external_library
#import external_library
reload(external_library)
external_library.the_best()
output
The best!
Upvotes: 1
Reputation: 28370
Monkey patching works because classes are modifiable in python but the mechanism that allows it to spread like this is that once any module has been imported, and initialised, later imports simply add the existing instance to the local namespace without rerunning the initialisation, this also saves time when a module has a lot of initialisation as well as allowing monkey patches.
Upvotes: 0
Reputation: 881635
Nothing thread-local about this. somemodule.anattr = avalue
is very global behavior! After this assignment the attribute is changed for good (until maybe changed back later) no matter what.
There's no mysterious mechanics at play! Assignment to any attribute of an object that allows such assignment (as module objects do) just work in the obvious way -- no thread-local anything, nothing strange -- and assignment to attribute persists, as long as the object whose attribute you've assigned persists, of course.
The repeated import external_library
doesn't reload the module (reload
is a totally separate builtin and import
does not call it!) -- it just checks sys.modules
, finds an external_library
key in that dict
, and binds the corresponding value (which was previously modified by that assignment) to name external_library
in the appropriate namespace (here, globals of module main
).
Upvotes: 10