One function calling another defined in the same file being exec'd

Mitchell L Model MLMDev at Comcast.net
Fri Jan 8 12:13:34 EST 2010


On Jan 8, 2010, at 9:55 AM, "Gabriel Genellina" <gagsl- 
py2 at yahoo.com.ar> wrote:

>
> 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 is very helpful additional information and clarification! Thanks.

>
> This shows that the identity "globals() is locals()" is essential  
> for the module system to work.

Yes, though I doubt more than a few Python programmers would guess  
that identity.

>
>> [2] Is this correct behavior or is there something wrong with  
>> Python here?
>
> It's perfectly logical once you get it... :)

I think I'm convinced.

>
>> [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)
>

I was going to say that this wouldn't work because the script couldn't  
use any built-in names, but the way exec works if the value passed for  
the globals argument doesn't contain an entry for '__builtins__' it  
adds one. I would have a further problem in that there are some names  
I want users to be able to use in their scripts, in particular classes  
that have been imported into the scope of the code doing the exec, but  
come to think of it I don't want to expose the entire globals()  
anyway. The solution is do use the same dictionary for both globals  
and locals, as you suggest, to emulate the behavior of module import,  
and explicitly add to it the names I want to make available (and since  
they are primarily classes, there are relatively few of those, as  
opposed to an API of hundreds of functions). Thanks for the help.




More information about the Python-list mailing list