# PEP 266: Optimizing Global Variable/Attribute Access

Alex Martelli aleaxit at yahoo.com
Wed Aug 15 10:03:31 CEST 2001

```"Peter Caven" <p.caven at ieee.org> wrote in message
news:5rpe7.42284\$O8.6453125 at news1.busy1.on.home.com...
...
>         l = []
>         f = l.append
>         m = math.sin
>         for i in range(10):
>             f(m(i))
...
> Unless I'm missing something fundamental, if the compiler can be made
smart
> enough to know where to put TRACK_OBJECT and UNTRACK_OBJECT then why can't
> it do the code transformation as above?

It's very hard for the compiler to prove that this transformation does
not alter the semantics -- specifically that neither f nor m alter what
l.append and math.sin should resolve to!

Consider the following silly code:

import math
realsin = math.sin
def blah(f):
print 'blah!',f
math.sin = realsin
math.sin = blah

for i in range(10):
print math.sin(i)

C:\Code>python aa.py
blah! 0
None
0.841470984808
0.909297426826
0.14112000806
-0.756802495308
-0.958924274663
-0.279415498199
0.656986598719
0.989358246623
0.412118485242

Now, if the compiler hoisted math.sin out of the loop, it would
alter the semantics to printing "blah!" then None every time.

Now, here I've placed all the code inline so it may look like
the compiler COULD deduce that this math.sin is peculiar --
but that's a rather unusual case.

So, if Python's dynamic semantics are to stay untouched, any
caching or hoisting of method resolution MUST track potential
modifications.  Of course, the antecedent of this hypothetical
sentence is pretty iffy -- but, one COULD construct a case.

Say that instead of math.sin you're calling mymod.bigfun,
and this function needs to do very different work the very
first time it's called, e.g. just-in-time loading of some big
data table to use for interpolation; rather than weighing down
every call with an if to test if the table is already loaded, the
function could perhaps rebind its name to a slimmer function
after it's done loading the interpolation table.

Python's current highly-dynamic nature has its pluses as
well as its minuses.  SOME of the dynamic aspects are going
away in future releases, but it's still uncertain exactly which
ones, and SOME of them will (one may hope) remain.  Thus,
the compiler needs to do more work for optimization, when
compared to a compiler for a less-dynamic language.  The
idea of tracking-opcodes seems to me a brilliant compromise
between expending a LOT of work on the compiler, to enable
it to infer what changes and when, and just giving up on
optimization in the vast majority of cases, where Python is
just too dynamic to allow optimization without tracking.

Alex

```