覆盖从其他模块导入的函数中的全局变量

发布于 2021-01-29 15:02:09

假设我有两个模块:

py

value = 3
def x()
    return value

b.py

from a import x
value = 4

我的目标是使用a.xin的功能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
    

这给我要避免的用户增加了负担,并不能真正解决问题。

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

关注者
0
被浏览
95
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    我已经通过猜测和检查以及研究的结合提出了一个解决方案。您几乎可以完全按照我在问题中的建议进行操作:复制函数对象并替换其__globals__属性。

    我正在使用Python
    3,因此这是上面链接的问题的答案的修改后的版本,带有一个覆盖全局变量的附加选项:

    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__现有功能对象的引用不能更改:为什么func
    .__ globals__被记录为只读?



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看