覆盖从另一个模块导入的函数中的全局变量

2023-12-02

假设我有两个模块:

a.py

value = 3
def x()
    return value

b.py

from a import x
value = 4

我的目标是使用以下功能a.x in b,但更改函数返回的值。具体来说,value将被查找a作为全局名称的来源,即使我运行b.x()。我基本上是想在中创建函数对象的副本b.x这与a.x但使用b获取其全局变量。有没有一种相当简单的方法来做到这一点?

这是一个例子:

import a, b

print(a.x(), b.x())

目前的结果是3 3,但我希望它是3 4.

我想出了两种可行的复杂方法,但我对其中一种都不满意:

  1. 重新定义x在模块中b使用复制和粘贴。真正的功能比显示的要复杂得多,所以这不适合我。
  2. 定义一个可以传递给 x 的参数并仅使用模块的值:

    def x(value):
        return value
    

    这给用户增加了我想避免的负担,并没有真正解决问题。

有没有办法以某种方式修改函数获取全局变量的位置?


我通过猜测、检查和研究得出了一个解决方案。您几乎可以按照我在问题中提出的建议进行操作:复制函数对象并替换其__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__)

The __globals__属性是只读的,这就是为什么它必须传递给构造函数FunctionType. The __globals__无法更改现有函数对象的引用。

后记

我已经使用它足够多次了,现在它已在我编写和维护的实用程序库中实现,称为haggis. See haggis.objects.copy_func.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

覆盖从另一个模块导入的函数中的全局变量 的相关文章

随机推荐