覆盖从另一个模块导入的函数中的全局变量 [英] Override globals in function imported from another module
问题描述
假设我有两个模块:
a.py
value = 3
def x()
返回值
b.py
来自导入x
值= 4
我的目标是使用 ax
在 b
中,但改变函数返回的值。具体而言,即使在运行时,
。我基本上试图在 value
也会被查找为 a
作为全局名称的来源> BX() bx
中创建一个与 ax
相同但使用<$ c的函数对象的副本$ c> b 来获取它的全局变量。有没有相当直接的方法来做到这一点?
以下是一个例子:
import a,b
print(ax(),bx())
结果目前是 3 3
,但我希望它是 3 4
。
我已经提出了两种复杂的方法,但我对任何一种方法都不满意:
- 使用复制和粘贴在模块
b
中重新定义x
。真正的函数比所示的复杂得多,所以这并不适合我。 定义一个可以传入x的参数,并使用模块的值:
def x(价值):
返回值
这增加了我想避免的用户负担,并且不能真正解决问题。
有没有办法修改函数以何种方式获取其全局变量?
我已经通过猜测与检查和研究的混合来提出解决方案。您可以完全按照我在问题中提出的建议:复制函数对象并替换它的 __globals __
属性。
我使用Python 3,所以这里是 answer 回答上面提到的问题,并添加一个选项来覆盖全局变量:
import copy
导入类型
导入functools
$ b def copy_func(f,全局变量=无,模块=无):
基于https:如果globals是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)
如果模块不是无:
g .__ module__ = module
g .__ kwdefaults__ = copy.copy(f .__ kw defaults__)
return g
b.py
from a import x
value = 4
x = copy_func(x,globals(),__name__)
__ globals __
属性是只读的,这就是为什么它必须传递给 FunctionType
的构造函数。现有函数对象的 __ globals __
引用无法更改:为什么是func。 __globals__记录为只读?。
Let's say I have two modules:
a.py
value = 3
def x()
return value
b.py
from a import x
value = 4
My goal is to use the functionality of a.x
in b
, but change the value returned by the function. Specifically, value
will be looked up with a
as the source of global names even when I run b.x()
. I am basically trying to create a copy of the function object in b.x
that is identical to a.x
but uses b
to get its globals. Is there a reasonably straightforward way to do that?
Here is an example:
import a, b
print(a.x(), b.x())
The result is currently 3 3
, but I want it to be 3 4
.
I have come up with two convoluted methods that work, but I am not happy with either one:
- Re-define
x
in moduleb
using copy-and paste. The real function is much more complex than shown, so this doesn't sit right with me. Define a parameter that can be passed in to x and just use the module's value:
def x(value): return value
This adds a burden on the user that I want to avoid, and does not really solve the problem.
Is there a way to modify where the function gets its globals somehow?
I've come up with a solution through a mixture of guess-and-check and research. You can do pretty much exactly what I proposed in the question: copy a function object and replace its __globals__
attribute.
I am using Python 3, so here is a modified version of the answer to the question linked above, with an added option to override the globals:
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__
attribute is read-only, which is why it must be passed to the constructor of FunctionType
. The __globals__
reference of an existing function object can not be changed: Why is func.__globals__ documented as read-only?.
这篇关于覆盖从另一个模块导入的函数中的全局变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!