class derived from dict in eval

Alex Martelli aleax at aleax.it
Sat Mar 1 08:04:51 CET 2003


Aahz wrote:

> In article <nNw6a.308773$AA2.11749597 at news2.tin.it>,
> Alex Martelli  <aleax at aleax.it> wrote:
>>
>>You have to prepare a real dictionary for the names used
>>in the expression you're interested in, because, as others
>>said responding to you, the LOAD_NAME operation bypasses
>>polymorphic behavior and goes for actual dict item access.
>>
>>Fortunately, it's not too hard:
>>
>>def evalWithSpecialDict(expression, specialDict):
>>    compiled = compile(expression, '<string>', 'eval')
>>    realDict = {}
>>    for varname in compiled.co_names:
>>        realDict[varname] = specialDict[varname]
>>    return eval(compiled, realDict)
> 
> You're sick.  You need help.

Hmmm, I guess I'll take that as a compliment.  However, as
Andrew pointed out, this doesn't work right if the expression
can include qualified names, e.g. an expression strings of
        "foo.bar"
will have TWO items in co_names -- 'foo' _and_ 'bar'.  This
means the above code won't work right -- consider:

class foo:
    bar=23
    def __getitem__(self, name):
        if name=='foo': return self
        raise KeyError

evalWithSpecialDict('foo.bar', foo())

this will die with a KeyError when trying to access
key 'bar' in the mapping, unnecessarily.  So at the very
least we need to ignore this kind of things:

def betterEval(expression, specialDict):
    compiled = compile(expression, '<string>', 'eval')
    realDict = {}
    for varname in compiled.co_names:
        try: realDict[varname] = specialDict[varname]
        except KeyError: pass
    return eval(compiled, realDict)


As Andrew also noticed, this is still imperfect in
some cases, i.e., consider:

class foo:
    bar=23
    def __getitem__(self, name):
        if name=='foo':
            return self
        elif name=='bar':
            time.sleep(10800)
            return 999
        raise KeyError

Now, betterEval('foo.bar', foo()) does succeed, but
it wastes 3 hours of elapsed time it wouldn't need,
because it asks foo() for the toplevel name 'bar'
which it doesn't really need.


So, I _did_ get help, and enhanced this approach, but
for the case of expressions that use qualified names,
and mappings that may take a lot of computational
effort to produce the values for some of their keys,
it's hard to see how to make things satisfactory...


Alex





More information about the Python-list mailing list