首页 > 解决方案 > 如何覆盖第三方库使用的方法

问题描述

这将是布局

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()

主文件

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,那么是否可以用其他东西覆盖它,而无需重新实现整个类?

标签: python

解决方案


您在这里提供的关于您的用例的信息非常少。正如其中一条评论指出的那样,这可能是继承的情况。如果您在测试环境中,您可能不想使用继承,但您可能更愿意使用模拟对象。

这是继承版本:

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从类派生。这样,类继承了所有的功能,类的定义只包含与 不同的部分。在您的示例中,这就是该方法应该调用而不是.Aclass B(A)BABBAxxxnew_some_functionsome_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_functionnew_some_function甚至可能比实际需要的要多。也许,您只想要一个可以调用并且始终返回相同值的空外壳(而不是side_effect行,您可以指定一个常量.return_value在上面的代码示例中)。模拟对象的关键功能之一是您可以稍后检查该函数是否已被调用。如果测试是您的用例,我非常建议您查看 python 模拟模块的文档。

请注意,该示例使用mock.patch上下文管理器。这意味着在托管上下文中(即 - 语句中的块withsome_library.some_function被模拟对象替换,但是一旦您离开托管上下文,原始功能就会恢复原状。


推荐阅读