newbie wants to eval()

Alex Martelli aleaxit at yahoo.com
Sun Jul 1 05:32:32 EDT 2001


"lynx" <noone at nowhere.net> wrote in message
news:3b3e655b$0$88181$2c3e98f8 at news.voyager.net...
    ...
> > You'd need to use the 'exec' statement (shudder), but fortunately you
> > can easily do better than that, since...:
>
> hmm. is there something inherently evil about exec that i should know
> about...?

In a sense, it's "too powerful" -- it can do so many things that it's bound
to have unpleasant fallback in some way or other.  Clarity and ease of
understanding your program is likely to be the main casualty, but there
may be others.

For example: usually, the compiler is able to perform a simple but
crucial optimization for local variables of your functions -- it knows
what variables are local (all that are bound in local scope), and it
needs not insert lookup operations for local variable access into the
bytecode it generates.  But if the function contains an exec, all
bets are off -- the compiler DOES need to insert explicit lookups,
so all of the function is slowed down.

So, use exec when you must, but be aware that you RARELY 'must',
and there are usually better alternatives.  If and when you do use
exec, it's generally best to use explicit dictionaries as namespaces,
to avoid accidents and slow-downs.


> > Global variables are really attributes of an object, the module object
> > to be precise.  Setting any object's attributes is most easily done via
> > built-in function setattr().
>
> > So you need a reference to the object that's the module you want to
> > affect.  Assuming this is the module containing the function you're
> > writing, simplest may be:
> >     import sys
> >     mymod = sys.modules[__name__]
> > and now mymod is the reference you require.
>
> looks interesting. should that snippet be run in the function where i'm
> trying to change these globals, or in the main program and that reference
> passed in as an argument to the function?

Either will work.  Having it in your function will make it simpler to use.
Having it on the outside makes your function more general, since it
can be called with different module-object arguments to set global
variables in different modules (or attributes of other objects yet).  A
person with any knack for overgeneralization would have mymod as
an optional argument with a default value of None and do the above
only if mymod is None...:-).


> honestly, myself, i'd be more upset and shuddering at this kind of
> manual rooting around in Python's own internal workings than at the
> exec() statement, which seems designed to hide this sort of magic from
> me; unless, of course, there's something strange about exec that i don't
> know of...?

Python is an unusual high-level language in that it DOES expose and
document a wide part of how it internally goes about things, and quite
explicitly empowers you to "root around" that part.  It does mean one
must employ good taste and common sense to avoid making one's
code a mess of hard-to-understand, hard-to-maintain black magic, yes.

But "exec" is still overkill for most things you can do by other means.

Specifically, when you think you need exec or eval to bind or access
variables whose names you don't know in advance, setattr and getattr
are very likely to be a better choice.  Whether they must go to a module
object is another issue; often you're better served by keeping such
variables as attributes of _your own_ object that you fully control, and
that will most often be an instance object rather than a module object,
because instance objects can check their own attributes via special
methods __getattr__ and __setattr__ -- and you may not even need
that much.

Suppose you keep all of your configuration variables this way:

class Config:
    one = 1
    another = 23
    andalso = 'feefie'
config=Config()

Now you can elsewhere in your code check and use config.one,
config.another, config.andalso -- as the attributes are not specifically
bound in the instance, you'll get the class ones.  You can also
allow user-configuration code to set ANY attribute of config, no
checks needed -- if the user sets an attribute you're not using,
that's gonna be a no-op.  So you can for example:
    execfile("userconf.py", vars(config))
and then use config.one, etc, and get either the instance variable
if user code has set it, or else the fallback class value.


Alex






More information about the Python-list mailing list