Re: accessing local and global dictionaries

Guido.van.Rossum@cwi.nl
Thu, 02 Mar 1995 14:57:40 +0100

Harri:
> > > # Example usage: define globals a,b and c, starting from 2.
> > > enum('a,b,c', 2)

Me:
> > This is accomplished just as easy using
> >
> > [a, b, c] = range(2, 2+3)

Harri again:
> This is what enum does internally.
>
> Modification is not quite as easy, as I now have to modify both
> sides of the equation mark if I want to add variables.
>
> enum('a, b, c, d', 2) vs. [a, b, c, d] = range(2, 2+4)
> ^ ^ ^
> If the list of identifiers is long, it becomes difficult trying to
> track down the length of the list that must be added manually to the
> range. (I'm just trying to mimic part of what enum { a = 2, b, c, d,
> ... } does in C.)

Agreed... At least Python will give you an exception when you get it
wrong!

> But my actual question concerned deciphering the dictionaries for
> different scopes. Any pointers there?

I was hoping I wouldn't have to answer that question, because it is
seriously "bad style" to define functions that modify their calling
environment directly (as opposed to returning a value that the caller
stores in a variable, or modifying an object, e.g. a dictionary,
passed to them as an argument).

Why don't you define your enum() function as taking a third argument,
a dictionary into which the new names are stored. You can then call
it (at the module level, at least) as:

enum('a,b,c', 2, vars())

The built-in vars() function returns the current dictionary. When
called at the module level, you can actually modify this dictionary to
your heart's content. (Inside functions, restrictions apply -- see
below.)

BTW, since you obviously want this as a shorthand, why don't you use
whitespace as the delimiter between the enum names in the string?
Then you can write:

enum('a b c', 2, vars())

which is a bit cleaner in my eyes, and allows you to format really
long lists using triple-quoted strings, e.g.

enum('''
a
b
c
''', 2, vars())

> > No 'enum()' function needed at all! (And the advantage is that the
> > optimizer knows which identifiers you are defining.)
>
> I don't understand what you imply about the optimizer. Are you saying
> that because these variables go into global scope, which is always
> looked at last, it is slower to access them?
>
> But if I want these identifiers to be global, I would think that both
>
> enum('a, b, c', 2)
>
> and
>
> [a, b, c] = range(2, 2+3)
>
> would create performance-wise equal variables. Am I missing something?

Well, I was thinking that perhaps you'd want to run this inside a
function, creating the enums as local names, and there you'd run into
some problems. There's an optimizer for local variable accesses. It
is very simple-minded: it first decides which variable names are ever
assigned to inside the function by looking at all assignments (and
local import statements and for statements etc.; it also takes care of
global statements of course) and then allocates space for the locals
in an array. All local variable references are then made by indexing
in this array instead of by dictionary lookups. If you had a function
that could add arbitrary names to the set of local variables, the
optimizer would no longer work. E.g. in

def f(i):
enum('a,b,c', 2)
if i < 0: return a
if i == 0: return b
return c

the optimizer doesn't see that a, b and c are locals, and this
generates code that only looks them up in the global scope (and
fails).

If you manage to shut the optimizer off (by including an exec
statement or a "from ... import *" statement in the function), local
variable references are implemented using dictionary lookup, so the
code would work, but variable references would be slower.

If you *really* need to get access to the caller's scope, try raising
and catching an exception and following the list of stack frames
back... Use something like sys.exc_traceback.tb_frame.f_back.f_locals
(or f_globals if you need the caller's global dictionary).

At the moment there's no optimizer for globals accesses. However,
this may change. I suppose that use of the vars() function will have
to disable this optimizer...

--Guido van Rossum, CWI, Amsterdam <mailto:Guido.van.Rossum@cwi.nl>
<http://www.cwi.nl/cwi/people/Guido.van.Rossum.html>