假设我有两个模块:
a.py
value = 3
def x()
return value
b.py
from a import x
value = 4
我的目标是在a.x
中使用b
的功能,但更改函数返回的值。具体而言,即使我运行value
,也会使用a
作为全局名称来查找b.x()
。我基本上试图在b.x
中创建一个与a.x
相同但使用b
获取其全局变量的函数对象的副本。有没有一种相当直接的方法呢?
以下是一个例子:
import a, b
print(a.x(), b.x())
结果目前为3 3
,但我希望它为3 4
。
我提出了两种复杂的方法,但我对其中任何一种都不满意:
x
中重新定义b
。真正的功能比显示的要复杂得多,所以这不适合我。定义一个可以传入x的参数,只需使用模块的值:
def x(value):
return value
这增加了我想避免的用户负担,并没有真正解决问题。
有没有办法修改函数以某种方式获取其全局变量的位置?
答案 0 :(得分:1)
所以我找到了一种方法(有点)这样做,虽然我不认为它完全解决了你的问题。使用inspect,您可以访问调用函数的文件的全局变量。因此,如果您设置文件如下:
<强> a.py 强>
import inspect
value = 3
def a():
return inspect.stack()[1][0].f_globals['value']
<强> b.py 强>
from a import a
value = 5
print(a())
输出为5,而不是3.但是,如果将这两个输入到第三个文件中,它将查找第三个文件的全局变量。只是想分享这个片段。
答案 1 :(得分:1)
我通过猜测和研究的混合物提出了一个解决方案。您可以完全按照我在问题中提出的内容执行操作:copy a function object并替换其__globals__
属性。
我正在使用Python 3,所以这里是上面链接的问题answer的修改版本,添加了覆盖全局变量的选项:
import copy
import types
import functools
def copy_func(f, globals=None, module=None):
"""Based on https://stackoverflow.com/a/13503277/2988730 (@unutbu)"""
if globals is None:
globals = f.__globals__
g = types.FunctionType(f.__code__, globals, name=f.__name__,
argdefs=f.__defaults__, closure=f.__closure__)
g = functools.update_wrapper(g, f)
if module is not None:
g.__module__ = module
g.__kwdefaults__ = copy.copy(f.__kwdefaults__)
return g
<强> b.py 强>
from a import x
value = 4
x = copy_func(x, globals(), __name__)
__globals__
属性是只读的,这就是它必须传递给FunctionType
的构造函数的原因。无法更改现有函数对象的__globals__
引用:Why is func.__globals__ documented as read-only?。
答案 2 :(得分:0)
我有同样的问题。但后来我想起eval
是一回事。
这是一个简短得多的版本(如果不需要参数):
b.py:
from a import x as xx
# Define globals for the function here
glob = {'value': 4}
def x():
return eval(xx.__code__, glob)
希望两年后仍然会有帮助