En Thu, 07 Jan 2010 19:47:13 -0300, Mitchell L Model <mlm...@comcast.net>
escribió:
def dofile(filename):
ldict = {'result': None}
with open(filename) as file:
exec(file.read(), globals(), ldict)
print('Result for {}: {}'.format(filename, ldict['result']))
Next I call dofile() on a slightly more complex file, in which one
function
calls another function defined earlier in the same file.
################################
def fn1(val):
return sum(range(val))
def fn2(arg):
return fn1(arg)
result = fn2(5)
################################
This produces a surprise:
NameError: global name 'fn1' is not defined
Ok - short answer or long answer?
Short answer: Emulate how modules work. Make globals() same as locals().
(BTW, are you sure you want the file to run with the *same* globals as the
caller? It sees the dofile() function and everything you have
defined/imported there...). Simply use: exec(..., ldict, ldict)
[1] How is it that fn2 can be called from the top-level of the script
but fn1
cannot be called from fn2?
Long answer: First, add these lines before result=fn2(5):
print("globals=", globals().keys())
print("locals=", locals().keys())
import dis
dis.dis(fn2)
and you'll get:
globals()= dict_keys(['dofile', '__builtins__', '__file__', '__package__',
'__name__', '__doc__'])
locals()= dict_keys(['result', 'fn1', 'fn2'])
So fn1 and fn2 are defined in the *local* namespace (as always happens in
Python, unless you use the global statement). Now look at the code of fn2:
6 0 LOAD_GLOBAL 0 (fn1)
3 LOAD_FAST 0 (arg)
6 CALL_FUNCTION 1
9 RETURN_VALUE
Again, the compiler knows that fn1 is not local to fn2, so it must be
global (because there is no other enclosing scope) and emits a LOAD_GLOBAL
instruction. But when the code is executed, 'fn1' is not in the global
scope...
Solution: make 'fn1' exist in the global scope. Since assignments (implied
by the def statement) are always in the local scope, the only alternative
is to make both scopes (global and local) the very same one.
This shows that the identity "globals() is locals()" is essential for the
module system to work.
[2] Is this correct behavior or is there something wrong with Python
here?
It's perfectly logical once you get it... :)
[3] How should I write a file to be exec'd that defines several
functions that
call each other, as in the trivial fn1-fn2 example above?
Use the same namespace for both locals and globals: exec(file.read(),
ldict, ldict)
--
Gabriel Genellina
--
http://mail.python.org/mailman/listinfo/python-list