Re: Another newbee question

Tim Peters (tim@ksr.com)
Tue, 12 Apr 94 20:28:55 -0400

> > [tim, asking about the LOAD_GLOBAL optimization]

> [guido]
> Looks fine to me, but ... may have forgotten a subtle detail.

That's my worry too. Last October you posted the following piece to the
list, in response to a question about why 'exec' worked strangely at that
time. There are two reasons to repeat an excerpt now: (1) it all but
says that you had _already_ implemented the LOAD_GLOBAL trick (so maybe
you did & got burned, & reading it again will jog your memory); &, (2) it's
a nice summary of the local-vs-global-vs-builtin resolution issues, which
were popular topics recently.

> [excerpt from "Re: Some python comments/questions",
> Wed, 13 Oct 1993 10:28:45 +0100]
> ...
> For example, if you write
>
> i = 1
>
> def func():
> j = 1
> return i, j
>
> then the "compiler" (which generates pseudo code for the Python
> interpreter) sees that there is a local variable j but no local
> variable i, so it will generate a local reference for returning j but a
> global reference for returning i. The reason for doing so is that this
> speeds up both kinds of references: global references don't first have
> to do an unsuccessful lookup in the dictionary of local variables, and
> (starting in 0.9.9) local references are speeded up by using an index
> into a list instead of a dictionary lookup. Note that any assignment
> by definition creates a local variable unless explicitly declared
> global first -- 'global' is in fact one of the few statements that is
> interpreted at compile time instead of at run-time. Also note that for
> this purpose the compiler keeps track of all local variables, but not
> of all global variables. Finally, for the really inquiring minds,
> built-in functions (e.g. len()) and names (i.e. None) are treated as
> globals here and they *do* suffer one unsuccessful lookup in the table
> of globals. This means you can override built-in names with local or
> global names. You can even change the set of built-in functions by
> modifying the built-in module 'builtin' (soon to be renamed to
> '__builtin__' to emphasize its special status, like '__main__').

The description of non-local resolution there isn't correct for Python
today, but is correct given the LOAD_GLOBAL patch. BTW, I believed that
every STORE_NAME would get changed to STORE_FAST, so didn't think there
was any analogous optimization for STORE_GLOBAL. I believed that
remaining DELETE_NAMEs could be changed to DELETE_GLOBALs, but didn't do
that just because I felt I'd spend more time typing the change in than it
would save in all executions of Python programs from now 'til the end of
time <wink -- but deleting a global name from inside a function has got
to be rare>.

> ... I'll install it locally and see if it breaks anything.

Still hasn't broken anything here yet, and does yield a speedup.

> > [what about speeding other sorts of name resolution?]

> Without having firm data, I believe this discussion is getting way out
> of hand.

Agreed, & even better I'll shut up until I _have_ firm data <smile>.

> [some known inefficiencies that could be addressed]
> ...
> I can't remember the details, but seem to remember that the last timed
> I profiled Python, malloc and free calls drowned all others. I somehow
> can't believe that making symbols unique will speed name lookup that
> much.

I'd be surprised by that too, but wouldn't be surprised to see a real
speedup if a trick analogous to the LOAD_FAST/STORE_FAST local-reference
trick could be pulled off (i.e., replacing "lookup" by call-free, hash-
free, search-free, loop-free indexing in the main evaluation loop). That
would be a massive change! But I'm not sure it's impossible, given two
levels of indexing (one to map a module-local index to a "system" index,
and from there to the real value) ...

Whatever, the point is that you can speed up whatever you set your mind
to speeding up; the wisdom's in finding the right things to tackle ...

> > [whether or not to print raw expressions]

> ... Maybe I can convince myself that it is a good idea NOT to print
> such expressions *except* when they occur as top-level expressions
> typed at an interactive command prompt.

I'd be happy with that!

> ... Then the silly -k switch can also go.

If you do decide to go that route, it would be nice to add a temporary
(say, for one release) switch that, when explicitly enabled, continued
printing raw expressions but also sprayed a msg to stderr (with file &
line number) saying that this behavior is obsolete & will go away Real
Soon.

I _have_ seen Python code that relies on this behavior, but very rarely;
it will be hard for people using it to track down where they're doing it
without some help (since there's no simple grep'able way to search for
it).

> If I don't convince myself I'll add "pass [expression]" to the
> language as the recommended way to suppress the printing.

Ugh. Apart from being able to write

pass out
and
pass the_potatoes, please

that's kinda ugly.

the-most-beautiful-girl-in-the-world-ly y'rs - tim

Tim Peters tim@ksr.com
not speaking for Kendall Square Research Corp