AW: ByteCode Questions
Stefan Schukat
SSchukat at dspace.de
Wed Aug 22 03:48:04 EDT 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