替换Python

时间:2017-11-11 10:47:45

标签: python

我正在使用一段看起来像这样的代码:

# This code is not modifiable

from package import distance as dist

class A:
    def calculate(self):
        ...
        # call to dist()
        ...

我的代码:

from package import A

a = A()
a.calculate()

如您所见,distance()函数是在代码顶部导入的。班级A会调用distance()函数。它是在几个地方,而不仅仅是calculate()

我希望班级使用我的自定义距离功能。但是,该类不允许我在构造函数中传递它,我无法修改A的代码。我该怎么做?这是否可以通过子类化?我尝试了以下,但没有用:

from package import A

class B(A):
    def __init__(self):
        from mypackage import mydistance as dist
        return super().__init__()

b = B()
b.calculate()

3 个答案:

答案 0 :(得分:1)

您可以使用mock.patch功能,如下所示:

distance.py:

def distance():
    print('distance called')

mydistance.py:

def mydistance():
    print('mydistance called')

a.py:

from distance import distance as dist


class A:
    def calculate(self):
        dist()

main.py:

from unittest import mock

from a import A
from mydistance import mydistance


class B(A):
    def calculate(self):
        with mock.patch('a.dist', wraps=mydistance):
            super().calculate()


if __name__ == '__main__':
    b = B()
    b.calculate()

输出是:

mydistance called

根据您的使用情况,您可能希望将with语句放在其他位置(例如在呼叫站点中)。例如:

if __name__ == '__main__':
    b = B()
    with mock.patch('a.dist', wraps=mydistance):
        for _ in range(0, 100):
            b.calculate()

修补会导致一些开销。另一个解决方案(与oetoni建议基本相同)是重新分配属性(记住import a):

if __name__ == '__main__':
    b = B()
    old_dist = a.dist
    a.dist = mydistance
    for _ in range(0, 100):
        b.calculate()
    a.dist = old_dist

答案 1 :(得分:0)

您可以立即从代码中执行此操作,而无需添加新导入或使用mock.patch或任何第三类B.立即从您引用A的代码中

现在您只需要对代码进行一些小改动,不要只做from package import A,而是直接导入import baseA,这样我们就可以控制导入中的所有变量;)因此我们可以。然后我们可以使用它的局部变量名来捕获它并在运行时更改它:D如下:

在导入A

时假设distance()函数

<强> distance.py

def distance(something):
    return something + 1

然后我假设包含A类的文件名为baseA

<强> baseA.py

# This code is not modifiable

from distance import distance as dist


class A:
    def calculate(self):
        something = dist(1)
        return something

最后你编码包含你运行代码的文件,以及我们想要修改它在baseA中导入的dist()的地方

<强> yourcode.py

import baseA


def newDist(something):
    return something + 2


baseA.dist = newDist
a = baseA.A()


something = a.calculate()
print(something)

我成功地设法改变了baseA中dist的行为:) baseA.dist = newDist记得不要括号,因为我们将函数作为对象传递,以便将其行为分配给从 distance.py baseA.dist >文件

测试解决方案

enter image description here

答案 2 :(得分:-1)

您可以使用unittest.mock中的patch@装饰器来完成此操作。