Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

hierarchical namespaces in custom python modules

Tried searching the site, but cannot find an answer to my problem:

Lets say I have a module, named mymodule.py that contains:

def a():
    return 3

def b():
    return 4 + a()

Then the following works:

import mymodule
print(mymodule.b())

However, when I try defining the module contents dynamically:

import imp

my_code = '''
def a():
    return 3

def b():
    return 4 + a()
'''

mymodule = imp.new_module('mymodule')
exec(my_code, globals(), mymodule.__dict__)
print(mymodule.b())

Then it fails in function b():

Traceback (most recent call last):
File "", line 13, in <module>
File "", line 6, in b
NameError: global name 'a' is not defined

I need a way to preserve the hierarchical namespace searching in modules, which seems to fail unless the module resides on disk.

Any clues as to whats the difference?

Thanks, Rob.

like image 374
rbairos Avatar asked Jul 10 '26 20:07

rbairos


1 Answers

You're close. You need tell exec to work in a different namespace like so (see note at bottom for python 3.x):

exec my_code in mymodule.__dict__

Full example:

import imp

my_code = '''
def a():
    return 3

def b():
    return 4 + a()
'''

mymodule = imp.new_module('mymodule')

exec my_code in mymodule.__dict__
print(mymodule.b())

This said, I've not used this before, so I'm not sure if there are any weird side-effects to this, but it looks like it works to me.

Also, there's a small blurb about 'exec in ...' in the python docs here: http://docs.python.org/reference/simple_stmts.html#the-exec-statement

Update

The reason your original attempt didn't work correctly is you were passing your current module's globals() dictionary, which is different than the globals() your new module should use.

This exec line also works (but isn't as pretty as the 'exec in ...' style):

exec(my_code, mymodule.__dict__, mymodule.__dict__)

Update 2: Since exec is now a function in python 3.x, it has no 'exec in ...' style, so the line above must be used.

like image 174
Adam Wagner Avatar answered Jul 13 '26 11:07

Adam Wagner