funcs vs vars in global namespace

Bengt Richter bokr at oz.net
Tue Sep 14 16:57:53 EDT 2004


On Tue, 14 Sep 2004 14:25:04 -0400, David Rysdam <drysdam at ll.mit.edu> wrote:

>Alex Martelli wrote:
>> David Rysdam <drysdam at ll.mit.edu> wrote:
>>    ...
>> 
>>>OK, dumb question #1:
>>>
>>>Why do this:
>>>
>>>sub_module = __import__(which_module_this_time)
>>>vars(sub_module).update(which_dict_this_time)
>>>
>>>When I could just do this:
>>>
>>>__import__(which_module_this_time, which_dict_this_time)
>>>
>>>?
>> 
>> 
>> You can do whatever you wish, but what makes you think these constructs
>> have similar effects?  Quoting from Python's online docs on __import__,
>> 
>> """
>>  the standard implementation  does not use its locals argument at all,
>> and uses its  globals only to determine the package context of the
>> import statement
>> """
>> 
>> In short, the standard implementation of __import__ does NOT alter in
>> any way the dict of the module it imports.
>> 
>> 
>> Alex
>
>Ah, I see.
>
>Your "which_dict_this_time" dictionary, how are you imagining that 
>working?  I was just mapping function name strings to functions 
>({'logError':logError}), but (long story short) that isn't working how I 
>want.  But shouldn't I be able to define the function right there in the 
>dictionary itself?
>
>Perhaps this is getting too non-obvious, magical and unmaintainable, though.

Maybe this will give you some ideas:

Here empty.py is just a single blank text line with a (windows in this case, which
for the heck of it I'll show in binary) EOL:
 >>> open('empty.py','rb').read()
 '\r\n'

 >>> import empty
When you import, you automatically get some stuff in the module directory
 >>> dir(empty)
 ['__builtins__', '__doc__', '__file__', '__name__']
 >>> vars(empty).keys()
 ['__builtins__', '__name__', '__file__', '__doc__']

If you have source defining a function, you can exec the definition in a directory,
which will become what the function sees as its global directory. So,

 >>> exec """
 ... def foo(a):
 ...     return a+b
 ... """ in empty.__dict__

It shows up:

 >>> dir(empty)
 ['__builtins__', '__doc__', '__file__', '__name__', 'foo']

since b is retrieved from the global dict, we better put something there.
That happens to be the dict that stores module attributes, so we can:

 >>> empty.b = 100
 >>> empty.foo(23)
 123
 >>> empty.b = 200
 >>> empty.foo(23)
 223
... as expected.

We can verify that foo's global dict is empty's dict:
 >>> empty.foo.func_globals is empty.__dict__
 True

If you have definitions of functions in source files, you can execfile them
in a similar manner:

First I'll creat a source right here, though I could have done it in an editor
 >>> open('baz.py','w').write("""
 ... def baz(x):
 ...     return 2*b+x
 ... """)

Verify
 >>> print '----\n%s----'%open('baz.py').read()
 ----

 def baz(x):
     return 2*b+x
 ----

Use execfile do define it in empty:
 >>> execfile('baz.py', empty.__dict__)

It shows up:
 >>> dir(empty)
 ['__builtins__', '__doc__', '__file__', '__name__', 'b', 'baz', 'foo']

Check b:
 >>> empty.b
 200
 >>> empty.baz(44)
 444

HTH. Note that exec-ing or execfile-ing untrusted source is not safe.

BTW, if in the same interpreter execution session you import empty from another module,
the updated contents should be visible. E.g.,

 >>> open('mimpbaz.py','w').write("""import empty
 ... """)
 >>> print '----\n%s----'%open('mimpbaz.py').read()
 ----
 import empty
 ----
 >>> import mimpbaz
 >>> dir(mimpbaz)
 ['__builtins__', '__doc__', '__file__', '__name__', 'empty']
 >>> mimpbaz.empty is empty
 True
 >>> mimpbaz.empty.b
 200
 >>> mimpbaz.empty.baz(3056)
 3456

recalling that baz did
 >>> 2*200+3056
 3456

Note that the source of empty.py has not changed
 >>> print '----\n%s----'%open('empty.py').read()
 ----

 ----
 >>> open('empty.py').read()
 '\n'

Of course, it doesn't have to start out empty. The point is
exec and execfile don't save a compiled .pyc for you to make
it faster next time, whereas import does (unless it's prevented
by lack of write privilege or such, I think).

Regards,
Bengt Richter



More information about the Python-list mailing list