Why is Python so slow ?- revisited.

Thomas Wouters thomas at xs4all.nl
Sat Jun 24 12:02:12 EDT 2000


On Thu, 22 Jun 2000 17:20:10 -0400, Bijan Parsia <bparsia at email.unc.edu> wrote:
>Michael Hudson <mwh21 at cam.ac.uk> wrote:

>> Certainly at some point there was no LOAD_FAST opcode; every name
>> lookup would first look into a local dict, then the global one, then
>> the builtins.  Now references to locals are just indexes into (C)
>> vectors; this is much quicker.

>Ah! Thanks! Am I correct in surmising from this that the gap between a
>local access success and a miss (but hitting somewhere up the chain) is
>even greater (than before LOAD_FAST)? Hmm.

'Optimized' local accesses are very unlikely to fail, because the compiler
has already assured the name exists, locally, or it wouldn't have turned it
into a LOAD_FAST :) What can happen is that an UnboundLocalError occurs;
this happens when you use a variable before you assign to it.

What happens is this: When you use a variable (by name) in Python code, the
compiler compiles it into a LOAD_NAME bytecode. The name you try to load
gets added to the 'co_names' tuple in the func_code code-block of the
function, and the LOAD_NAME bytecode takes an index into that tuple as
argument. This is the same for all name lookups.

Then, after a function is fully compiled, the optimizer walks past all
bytecodes, taking note of all bytecodes that can introduce a name.
(STORE_NAME and IMPORT_FROM). If it sees an 'EXEC' or 'IMPORT_FROM' with '*'
as argument, it notes that too.

The list of variable names is turned into two tuples, one to hold the names
and one to hold the values, and all bytecodes that refer to one of these
local variables are translated from '(LOAD|STORE|DELETE)_NAME <index in
namelist>' into '*_FAST <index in locals-values list>'. If no 'exec' or
'from foo import *' was found, all other '*_NAME' bytecodes are translated
into '*_GLOBAL' bytecodes -- they aren't referring to local variables, so
they must be refering to global ones.

I'm not sure if the difference in speed is ever measured (I assume so, 'twas
probably before I was born anyway ;) but I'm fairly certain it's worth the
(actually pretty small!) impact on code-simplicity: the *_FAST bytecodes can
access the desired variable almost directly, using a simple index &
pointer-dereference operation. The *_GLOBAL bytecodes are slightly more
expensive, being a normal dictionary lookup. The *_NAME bytecodes are
definately more expensive, as they do a dictionary lookup in the 'locals'
dictionary, as well as the gobals dictionary if the locals fail. (Which is
fairly likely, because most local acceses will already have been translated
to *_FAST)

I'm-a-newbie-though-and-probably-incorrect--don't-take-my-word-for-it-ly yr's,
Thomas.



More information about the Python-list mailing list