func_code vs. string problem

Steven Bethard steven.bethard at gmail.com
Sat Apr 23 16:41:58 EDT 2005


Filip Dreger wrote:
> Each function has a func_code property that is suposed to contain the 
> pure bytecode of the function. All the context (including reference to 
> relevant namespaces) is stored in different fields of the function 
> object. Since 'exec' is able to execute any string or bytecode in the 
> current scope, it would seem possible to execute code of any function 
> in any namespace. But no matter how I tried, I could not do it. There 
> must be something I am missing.
> Here's what I do:    (if anyone wants to help, I placed the source 
> under http://www.bajobongo.net/foo.py - tested on Python 2.4.1)
> 
> 1. I declare a function. In the next steps I will try to run its code 
> from inside a class:
> 
> def myfunction():
>    print abc
>    self.test()
> 
> 2. I declare a class foo, with two methods. The first one tries to 
> reach some local variables from a string passed to exec. The other one 
> tries to do the same from inside a bytecode (from myfunction). IMHE 
> this should make no difference to 'exec' - [spoiler: it does].
> 
> class foo:
>    def test(self):
>       print "ABC"
>    def checkfunction(self):
>       abc=10
>       exec myfunction.func_code
>    def checkstring(self):
>       abc=10
>       exec "print abc;self.test()"
> 
> 3. I test the both methods. Sadly, the 'checkfunction' fails to find 
> the correct namespace (id does not see 'abc' nor 'self'). Adding 
> things like:
> "exec myfunction.func_code in globals(),locals()" does not help.
> 
> i=foo()
> i.checkstring()
> i.checkfunction()  # this throws exception; why???

See the documentation:

http://docs.python.org/ref/dynamic-features.html

"""The eval(), execfile(), and input() functions and the exec statement 
do not have access to the full environment for resolving names. Names 
may be resolved in the local and global namespaces of the caller. Free 
variables are not resolved in the nearest enclosing namespace, but in 
the global namespace."""

Note the last sentence, which tells you that your free variable, 'abc', 
will be resolved in the *global* namespace.  In your particular problem, 
you can solve this by substituting your local namespace for the global 
namespace:

py> def myfunction():
...     print abc
...     self.test()
...
py> class foo:
...     def test(self):
...         print "ABC"
...     def checkfunction(self):
...         abc=10
...         exec myfunction.func_code in locals()
...     def checkstring(self):
...         abc=10
...         exec "print abc;self.test()"
...
py> foo().checkstring()
10
ABC
py> foo().checkfunction()
10
ABC

But note that if your code actually needs access to any globals, it's 
out of luck:

py> def myfunction():
...     print foo
...     print abc
...     self.test()
...
py> foo().checkfunction()
Traceback (most recent call last):
   File "<interactive input>", line 1, in ?
   File "<interactive input>", line 6, in checkfunction
   File "<interactive input>", line 2, in myfunction
NameError: global name 'foo' is not defined

One possible workaround might be:

py> class foo:
...     def test(self):
...         print "ABC"
...     def checkfunction(self):
...         abc=10
...         l = locals()
...         l.update(globals())
...         exec myfunction.func_code in l
...     def checkstring(self):
...         abc=10
...         exec "print abc;self.test()"
...
py> foo().checkfunction()
__main__.foo
10
ABC

But I'd have to know what your real use case is to tell you whether or 
not this is worth the trouble.  Why do you want to exec the func_code 
anyway?  Why can't you just call the function?

STeVe



More information about the Python-list mailing list