AW: ByteCode Questions

Stefan Schukat SSchukat at dspace.de
Wed Aug 22 09:48:04 CEST 2001


> -----Ursprüngliche Nachricht-----
> Von: Skip Montanaro [mailto:skip at pobox.com]
> Gesendet: Dienstag, 21. August 2001 17:52
> An: Stefan Schukat
> Cc: python-list at python.org
> Betreff: Re: ByteCode Questions
> 
> 
> 
>     ...
>     Stefan> def Working():
>     Stefan>     EvalInCaller("a = 2\n")
>     Stefan>     exec("")
>     Stefan>     print a
> 
>     Stefan> def NotWorking():
>     Stefan>     EvalInCaller("a = 2\n")
>     Stefan>     print a
>     ...
> 
>     Stefan> So the question is why does Python take the 
> LOAD_GLOBAL byte
>     Stefan> code in the not working function and the 
> LOAD_NAME bytecode in
>     Stefan> the working version. How can I force the 
> LOAD_NAME bytecode
>     Stefan> dynamically or must I exchange all LOAD_GLOBAL to 
> LOAD_NAME in
>     Stefan> the codeblock used.
> 
> Python (before 2.1 came out with nested scopes, at least) 
> searches three
> namespaces for variables: the current function, the module in 
> which the
> function resides, then the module containing all builtin 
> functions.  There
> are three types of LOAD_* instructions:
> 
>     LOAD_FAST - when the compiler knows the variable reference is to a
>     variable local to the current function.  Values are found 
> in a local
>     variables array.
> 
>     LOAD_GLOBAL - when the compiler knows the variable 
> reference is not to a
>     variable local to the current function.  Values are found 
> by dictionary
>     lookup, first in the module's globals, then in the builtins.
> 
>     LOAD_NAME - when the compiler can't tell.  Values are found by
>     dictionary lookup first in the locals dict, then in the 
> globals dict,
>     then in the builtins.
> 
> When you execute an exec statement, it can put symbols in whatever
> namespaces you feed it as the globals and locals.  (You 
> shouldn't use parens
> with exec, BTW.  It's a statement, not a function.  Also, 
> exec's that don't
> list explicit globals and locals are not a great idea.)  The compiler
> short-circuits local variable lookup by indexing into an array in the
> current frame object.  That array is of a fixed size (determined at
> compile-time), so the compiler can only allocate an array 
> referencing the
> objects it knows are local to the current function.  There is 
> also a local
> variable dict, but in most cases (except when LOAD_NAME is 
> needed) it's not
> needed.
> 
> Your EvalInCaller function is effectively putting an exec 
> statement into the
> body of your function, but hiding it from the compiler, so 
> the "print a"
> statement generates a LOAD_GLOBAL bytecode to find "a".  (It 
> knows "a" was
> never set in the function, so it *must* be in the module 
> globals or the
> builtins as far as the compiler is concerned.)  When you add 
> an empty exec
> statement to the Working function, it signals the bytecode 
> compiler that any
> variables the function references that weren't set within the 
> function's
> body must be found the slowest way (LOAD_NAME).  Using "from 
> mod import *"
> within a function has the same cache-busting effect.  (In 
> 2.2, you get a
> SyntaxWarning error about that.  I think it will be elevated 
> to an error in
> 2.3.)
> 
> All that said, I'm not sure there's a good solution for your problem.
> 
> -- 
> Skip Montanaro (skip at pobox.com)
> http://www.mojam.com/
> http://www.musi-cal.com/

Thanks for the explanation. Probably I should think about other clearer
ways to introduce variables defined in an "upper" namespace. 

   Stefan





More information about the Python-list mailing list