0

Following this answer, I am using imp.new_module and exec to dynamically load a module and extract functions from it. However, when I store the module in a local variable, functions from it get broken. Here is an example:

import imp

mod = None
func = None

code = """
a = 42

def func():
    print a
"""

def main():
    #global mod
    global func
    mod = imp.new_module("modulename")
    exec code in mod.__dict__
    func = mod.func

main()
func()

Executing this with Python 2.7.3 yields None: codepad. After uncommenting global mod line, making mod global, the function works as expected and prints 42: codepad.

What am I missing? Why does the behaviour change when module is stored in a local variable?

Community
  • 1
  • 1
mpeterv
  • 463
  • 4
  • 11
  • From [docs](https://docs.python.org/2/reference/datamodel.html): ***CPython implementation detail**: Because of the way CPython clears module dictionaries, the module dictionary will be cleared when the module falls out of scope even if the dictionary still has live references. To avoid this, copy the dictionary or keep the module around while using its dictionary directly.* – Ashwini Chaudhary Jun 27 '14 at 10:44
  • I see that it's my fault not to look at the docs more carefully, thank you for a direct link. – mpeterv Jun 27 '14 at 10:50

1 Answers1

1

The mod module is a local, and not referenced anywhere else. Like all other objects in Python, that means it is cleaned up when main exits. By making it a global instead, a reference to the module object is kept.

When a module is cleaned up, all the globals are set to None (this is done to break reference cycles early, setting to None is an optimisation to prevent excessive rehashing due to dictionary resizing). The func object still has a reference to the module globals dictionary, and thus sees a bound to None now.

The normal procedure of importing a module adds a reference to the module object in sys.modules, keeping the module alive until interpreter shutdown.

(In Python 3.4, globals are no longer rebound to None (in most cases), as per Safe Object Finalization; see PEP 442).

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343