这就是布局
some_function.py
def some_function():
print("some_function")
some_library.py
from some_function import some_function
class A:
def xxx(self):
some_function()
main.py
from some_library import A
from some_function import some_function
def new_some_function():
print("new_some_function")
if __name__ == '__main__':
some_function = new_some_function
a = A()
a.xxx()
在类A
中,方法xxx
调用了some_function
,是否有可能用其他方法覆盖它而无需重新实现整个类?
答案 0 :(得分:2)
您在这里提供的用例信息很少。正如其中一项评论指出的那样,这可能是继承的情况。如果您处于测试环境中,则可能不希望使用继承,而是希望使用模拟对象。
这是继承版本:
from some_library import A
def new_some_function():
print("new_some_function")
class B(A):
def xxx(self):
new_some_function()
if __name__ == '__main__':
a = B()
a.xxx()
请注意,类B
是如何通过A
语句从类class B(A)
派生的。这样,类B
继承了A
的所有功能,并且类B
的定义仅包含B
与A
不同的部分。在您的示例中,事实是xxx
方法应调用new_some_function
而不是some_function
。
这是模拟版本:
from unittest import mock
from some_library import A
def new_some_function():
print("new_some_function")
if __name__ == '__main__':
with mock.patch('some_library.some_function') as mock_some_function:
mock_some_function.side_effect = new_some_function
a = A()
a.xxx()
如上所述,如果您处于测试环境中并且some_function
所做的事情代价昂贵和/或不可预测,则此方法最有用。为了测试涉及到对some_function
的调用的代码,您可能会暂时想用其他替换some_function
的方法,这种方法调用起来很便宜,并且行为可预测。实际上,对于这种情况,用some_function
代替new_some_function
甚至可能超出实际需要。也许,您只需要一个可以被调用且总是返回相同值的空壳(而不是side_effect
行,您可以在上面的代码示例中指定一个常量.return_value
)。模拟对象的关键功能之一是您以后可以检查该函数是否已被调用。如果测试是您的用例,我非常建议您查看python模拟模块的文档。
请注意,该示例使用mock.patch
上下文管理器。这意味着在托管上下文中(即with
语句中的块)some_library.some_function
被模拟对象代替,但是一旦离开托管上下文,原始功能就会恢复原位。
答案 1 :(得分:1)
我认为您正在寻找 monkey patching (意味着在运行时动态更改类/模块)。这样,您就无需覆盖类A
并使用其他注释所建议的继承-您表示不希望这样做,因此请尝试以下解决方案:
import some_class # import like this or will not work (cos of namespaces)
def new_some_function():
print("new_some_function")
if __name__ == '__main__':
# Import and use like this, other ways of import will not work.
# Because other way imports method to your namespace and then change it in your namespace,
# but you need to change it in the original namespace
some_class.some_function = new_some_function
那样,替换原始方法,然后其他类也将使用它。请注意,如果原始方法是类/实例方法,则需要使用适当的参数创建新函数,如下所示:
def new_some_function(self):
# for instance methods, you may add other args, but 'self' is important
def new_some_function(cls):
# for class methods, you may add other args, but 'cls' is important
答案 2 :(得分:0)
您可以只创建另一个类并覆盖所需的方法。
举个例子:
class myInt(int):
def __pow__(self, x):
return 0
a = myInt(10)
a+10 # 20
a**2 # 0
在这种情况下,a
是一个整数,可以访问int
类的所有方法,但是将使用我定义的__pow__
方法。
答案 3 :(得分:0)
您需要的是继承,您可以继承一个类,并且可以使用super方法继承所有父类函数。如果要覆盖父类函数,则只需在子类中提供具有相同名称的其他实现。
从some_library导入A
从some_function导入some_function
def new_some_function():
print("new_some_function")
class B(A):
def __init__(*args, **kwargs):
super().__init__(self)
pass
def xxx(self):
new_some_function()
if __name__ == '__main__':
a = B()
a.xxx()
Output:
new_some_function
you syntax may differ depending upon the python version.
In python3
class B(A):
def __init__(self):
super().__init__()
In Python 2,
class B(A):
def __init__(self):
super(ChildB, self).__init__()