How to execute a function inside a namespace?

Say I have the following dict:

In [6]: scope
Out[6]: {'bar': <function bar>, 'foo': <function foo>}

And fooand bar:

def foo():
    return 5

def bar(x):
    return foo() + x

I want to run bar(1), but he will need to find foo(). Is there a way to run bar()in the namespace scopeto find foo()?

I do not know exactly which function scope barwill be needed, so I need a general method for working barin the namespace scope. I have no source code and cannot change any function to accept a dict.

Functions seem to have an attribute __closure__, but it is immutable. There is also an attribute __globals__, but this only indicates globals(). I saw several answers on SO that updated locals(), but I would like to leave it locals()untouched.

eval scope, NameError foo:

In [12]: eval(scope['bar'](1), scope)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-12-f6305634f1da> in <module>()
----> 1 eval(scope['bar'](1), scope)

<string> in bar(x)

NameError: global name 'foo' is not defined

- , ?

+3
2

eval() , , . -, , , . -, scope eval() , .

, :

def foo():
    return 5

def bar(x):
    return foo() + x

scope = {'scope': {'bar': bar, 'foo':foo}}  # define self-referential scope
expression = "scope['bar'](42)"  # explicit reference to `scope`
print('eval({!r}, scope) returns {}'.format(expression, eval(expression, scope)))

eval() bar scope ( scope['scope']['bar']):

scope = {'bar': bar, 'foo':foo}
expression = 'bar(42)'
print('eval({!r}, scope) returns {}'.format(expression, eval(expression, scope)))
+2
source

One approach is to create new functions using a common global dictionary:

from types import FunctionType

def scopify(**kwargs):
    scoped = dict()
    for name, value in kwargs.items():
        if isinstance(value, FunctionType):
            scoped[name] = FunctionType(value.__code__, scoped, name)
        else:
            scoped[name] = value
    return scoped

scope = scopify(
    foo = lambda: baz,
    bar = lambda x: foo() + x,
    baz = 5,
)

>>> scope['foo']
5
>>> scope['bar'](10)
15
>>> scope['baz'] = 100
>>> scope['bar'](10)
110
+4
source

All Articles