替换Python中的所有函数调用

替换Python中的所有函数调用,python,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调用dist

我使用的代码如下所示:

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

您可以使用中的
patch@
decorator执行此操作。

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

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

导入时的假定距离()函数

距离.py

def distance(something):
    return something + 1
# This code is not modifiable

from distance import distance as dist


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


def newDist(something):
    return something + 2


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


something = a.calculate()
print(something)
然后我假设包含类A的文件名为baseA

baseA.py

def distance(something):
    return something + 1
# This code is not modifiable

from distance import distance as dist


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


def newDist(something):
    return something + 2


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


something = a.calculate()
print(something)
最后是一个代码文件,其中包含您正在运行的代码,以及我们要修改在baseA中导入的dist()的位置

yourcode.py

def distance(something):
    return something + 1
# This code is not modifiable

from distance import distance as dist


class A:
    def calculate(self):
        something = dist(1)
        return something
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

测试解决方案

您可以使用以下功能:

distance.py:

def distance():
    print('distance called')
def mydistance():
    print('mydistance called')
mydistance.py:

def distance():
    print('distance called')
def mydistance():
    print('mydistance called')
a、 py:

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建议的相同)是重新分配属性(记住导入一个
):


将另一个版本的
放在python路径的前面?你能改变包裹吗?@Jean-Françoisfare不,我真的不能改变包裹。它来自scipy Python,是一种动态语言,它的类、函数和可验证项存储在查找目录中,可以访问和修改。尝试执行类似导入包的操作;package.dist=lambda x:10然后再次尝试运行代码,查看代码是否已更新检查下面的答案;)我将在稍后发布屏幕截图。它就像一个符咒!