覆盖后续导入导入的函数?
Overriding functions imported by a subsequent import?
对于一个项目,我需要从一个模块中替换一个函数。我想通过以下最小示例来实现这一点
在mod.py
中定义了原函数,
def f():
print("mod.py")
应该被 mod2.py
中的 f2
覆盖,
import sys
def f2():
print("mod2.py")
sys.modules["mod"].f = f2
在main.py
中,我首先加载了原始函数,我立即对其进行了修补
from mod import f
import mod2
f() # I'm expecting "mod2.py", but get "mod.py" instead
__main__
的 globals() 中 f
的函数定义似乎不是对 sys.modules["mod"].f
的引用,这是我希望的。
如果在 main.py
中导入定义了 f
的模块,而不是 f
本身,我可以修补它
import mod
import mod2
print(mod.f()) # patched from mod2
但我想找到一个解决方案,它既可以在 main.py
中导入,也可以导入整个模块 (import mod
) 和函数本身 (from mod import f
)。
我还尝试通过 inspect.currentframe().f_back.f_locals
以某种方式修改父框架中的 locals()
但这似乎效果不佳,如果我找到这样的解决方案,我会觉得很麻烦,这会做我想要的。
原则上,Python 处理 import
的方式可行吗?
from mod import f
获取 mod.f
引用的对象,并添加绑定到当前 module 中名为 f
的新变量。该对象现在至少有两个引用,mod.f
和 f
。如果 mod.f
被重新分配,原始函数对象引用计数减 1,但它仍然被本地 f
引用,因此仍然是任何人取消引用时使用的对象 f
.
你可以有一个 module 知道你想做什么猴子补丁并让它导入 mod 和 mod2。然后先导入那个 module。事实上,mod2.py
可以 import mod
。这一切都相当脆弱,因为您的代码的用户需要知道要注意导入内容的顺序。
最好不要 from mod import f
。只需 import mod
并在需要时执行 mod.f
。在那种情况下,您没有对函数的不同引用,并且修补工作正常。
mod.py
def f():
print("original")
def other():
print("other in mod")
mod2.py
from mod import *
def f():
print("override")
main.py
#all of mod is in mod2, no need to import mod unless you need the original f()
import mod2
#if you do need the original f()
from mod import f
f() #original
mod2.f() #override
mod2.other() #other in mod
以程序方式覆盖所有这些东西很好,但使用 class 继承可能更有帮助。
class Mod:
def __init__(self):
pass
def f(self, data):
#do something with data
data.reverse()
print(f'in Mod {data}')
class Mod2(Mod):
def __init__(self):
Mod.__init__(self)
def f(self, data, skip=False):
if not skip:
#example of doing something that is not included in original f()
data.pop(0)
print(f'in Mod2 {data}')
super().f(data) #call the original f() that this f() overrides
m2 = Mod2()
m2.f([11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
#in Mod2 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
#in Mod [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
m2.f([11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1], True)
#in Mod [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
这是对 mod.py
中的函数进行猴子修补的好方法,这样它将影响 import mod2
之后 mod
的任何进一步导入。这是可行的,因为模块缓存在 sys.modules
中 — 但如果您按照所示进行操作,则不需要显式引用它。
mod.py
:
def f():
print("mod.py")
mod2.py
:
import mod
def f2():
print("mod2.py")
# Monkey-patch `mod` module.
mod.f = f2
main.py
:
import mod
import mod2 # Importing this applies the patch to the `mod` module.
mod.f() # Prints -> mod2.py
对于一个项目,我需要从一个模块中替换一个函数。我想通过以下最小示例来实现这一点
在mod.py
中定义了原函数,
def f():
print("mod.py")
应该被 mod2.py
中的 f2
覆盖,
import sys
def f2():
print("mod2.py")
sys.modules["mod"].f = f2
在main.py
中,我首先加载了原始函数,我立即对其进行了修补
from mod import f
import mod2
f() # I'm expecting "mod2.py", but get "mod.py" instead
__main__
的 globals() 中 f
的函数定义似乎不是对 sys.modules["mod"].f
的引用,这是我希望的。
如果在 main.py
中导入定义了 f
的模块,而不是 f
本身,我可以修补它
import mod
import mod2
print(mod.f()) # patched from mod2
但我想找到一个解决方案,它既可以在 main.py
中导入,也可以导入整个模块 (import mod
) 和函数本身 (from mod import f
)。
我还尝试通过 inspect.currentframe().f_back.f_locals
以某种方式修改父框架中的 locals()
但这似乎效果不佳,如果我找到这样的解决方案,我会觉得很麻烦,这会做我想要的。
原则上,Python 处理 import
的方式可行吗?
from mod import f
获取 mod.f
引用的对象,并添加绑定到当前 module 中名为 f
的新变量。该对象现在至少有两个引用,mod.f
和 f
。如果 mod.f
被重新分配,原始函数对象引用计数减 1,但它仍然被本地 f
引用,因此仍然是任何人取消引用时使用的对象 f
.
你可以有一个 module 知道你想做什么猴子补丁并让它导入 mod 和 mod2。然后先导入那个 module。事实上,mod2.py
可以 import mod
。这一切都相当脆弱,因为您的代码的用户需要知道要注意导入内容的顺序。
最好不要 from mod import f
。只需 import mod
并在需要时执行 mod.f
。在那种情况下,您没有对函数的不同引用,并且修补工作正常。
mod.py
def f():
print("original")
def other():
print("other in mod")
mod2.py
from mod import *
def f():
print("override")
main.py
#all of mod is in mod2, no need to import mod unless you need the original f()
import mod2
#if you do need the original f()
from mod import f
f() #original
mod2.f() #override
mod2.other() #other in mod
以程序方式覆盖所有这些东西很好,但使用 class 继承可能更有帮助。
class Mod:
def __init__(self):
pass
def f(self, data):
#do something with data
data.reverse()
print(f'in Mod {data}')
class Mod2(Mod):
def __init__(self):
Mod.__init__(self)
def f(self, data, skip=False):
if not skip:
#example of doing something that is not included in original f()
data.pop(0)
print(f'in Mod2 {data}')
super().f(data) #call the original f() that this f() overrides
m2 = Mod2()
m2.f([11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1])
#in Mod2 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
#in Mod [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
m2.f([11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1], True)
#in Mod [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
这是对 mod.py
中的函数进行猴子修补的好方法,这样它将影响 import mod2
之后 mod
的任何进一步导入。这是可行的,因为模块缓存在 sys.modules
中 — 但如果您按照所示进行操作,则不需要显式引用它。
mod.py
:
def f():
print("mod.py")
mod2.py
:
import mod
def f2():
print("mod2.py")
# Monkey-patch `mod` module.
mod.f = f2
main.py
:
import mod
import mod2 # Importing this applies the patch to the `mod` module.
mod.f() # Prints -> mod2.py