[Tutor] eval weirdness

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Mon Dec 2 03:32:02 2002


> >It appears that the following code causes __builtins__.__dict__ to be
> >assigned to self.names.  Can anyone help me understand what is going on
> >here?
> >
> >
> >class testclass:
> >    def __init__(self):
> >        self.names = {}
> >        eval('5 + 5', self.names, self.names)
> >        print self.names
> >
> >if __name__ == '__main__':
> >    testclass()

Hello Poor Yorick and Gregor!


Wow, this is weird!  I never would have expected eval() to touch the
dictionary that we feed in!  I'm looking in the C source code at the
eval() function... Yup, it's intentional:


/*** Within bltinmodule.c:builtin_eval ***/
...
if (PyDict_GetItemString(globals, "__builtins__") == NULL) {
	if (PyDict_SetItemString(globals, "__builtins__",
				 PyEval_GetBuiltins()) != 0)
		return NULL;
	}
...
/******/



... Ah ha!  Found the reason.  According to:

    http://www.faqts.com/knowledge_base/view.phtml/aid/4550/fid/538

the '__builtins__' module is inserted in deliberately so that normal
functions like like int() can still be used.

###
>>> d = {}
>>> eval("int(5.0) + 3", d)
8
>>>
>>> d = {'__builtins__': {}}
>>> eval("int(5.0) + 3", d)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<string>", line 0, in ?
NameError: name 'int' is not defined
###


Wow, that was a good question.  Thank you!




>  >>> what = __builtins__.__dict__['help']
>  >>> what
> Type help() for interactive help, or help(object) for help about object.
>  >>> type(what)
> <type 'instance'>
>  >>>
>
> Which class is what an instance of?


The help() 'function' is a little tricky --- it's actually an instance of
a class that's defined within the 'site.py' that runs automatically when
Python starts up:


### within site.py:
class _Helper:
    def __repr__(self):
        return "Type help() for interactive help, " \
               "or help(object) for help about object."
    def __call__(self, *args, **kwds):
        import pydoc
        return pydoc.help(*args, **kwds)

__builtin__.help = _Helper()
###

They've overridden '__repr__', so that when we just type 'help' at the
prompt, it returns that helpful usage message.  The implementers have also
overwritten the '__call__' method of help() so that __builtin__.help()
looks like a function, but it's actually a instance in disguise.



I hope this helps!