Python:替换模块类中的函数



我正在尝试替换类中定义的函数,以便在不更改实际代码的情况下修改其函数(如在内部工作中(。 我以前从未这样做过,因此在更换它时遇到了一些问题。

更改代码将让我访问 Python 库中的包,这不是一个选择。

例如,如果模块称为testMOD,

class testMOD(object):
def testFunc(self, variable):
var = variable
self.something = var + 12

然后我会导入testMOD,定义一个类(mytest = testMOD(((,并访问类testFunc中定义的函数testFunc,并将其更改为已经定义的函数。

例如

from somemodule import testMOD
mytest = testMOD()
def alternativeFunc(self, variable):
var = variable
self.something = var + 1.2
# A problem here
mytest.testFunc = alternativeFunc

如您所见,如果我只是用我定义的函数手动覆盖(?(类中的函数,它将无法正常工作。

它没有给出任何语法错误,但是,问题是被替换的函数认为"self"是函数的另一个变量,并说它需要"变量"变量的另一个参数(我想这不是一个好名字(。

我想使替换函数与替换函数完全相同,但使用额外的代码或一些小的修改。然而,"自我"在课堂上几乎没有像它应该的那样工作。

有没有办法正确实现定义的函数来替换导入类的函数?

我建议 4 种解决方案,从最差到最好(恕我直言(,但当然这也取决于您的具体约束:

替换实例方法 (1(: 我
  1. 利用函数在 Python 中是描述符的事实,这样我就可以在AlternativeFunc上使用__get__方法获取它作为实例mytest的方法,并覆盖实例mytesttestFunc方法(不覆盖类方法(:

    class testMOD(object):
    def testFunc(self, variable):
    var = variable
    self.something = var + 12
    print('Original:', self.something)
    def alternativeFunc1(self, variable):
    var = variable
    self.something = var + 1.2
    print('Alternative1:', self.something)
    mytest1 = testMOD()
    mytest1.testFunc(10)   # Original: 22
    mytest1.testFunc = alternativeFunc1.__get__(mytest1, testMOD)
    mytest1.testFunc(10)   # Alternative1: 11.2
    mytestX = testMOD()
    mytestX.testFunc(10)   # Original: 22
    
  2. 替换实例方法 (2(:这次,我使用比第一个解决方案更具可读性的types.MethodType

    import types
    class testMOD(object):
    def testFunc(self, variable):
    var = variable
    self.something = var + 12
    print('Original:', self.something)
    def alternativeFunc1(self, variable):
    var = variable
    self.something = var + 1.2
    print('Alternative1:', self.something)
    mytest1 = testMOD()
    mytest1.testFunc(10)   # Original: 22
    funcType = types.MethodType
    mytest1.testFunc = funcType(alternativeFunc1, mytest1)
    mytest1.testFunc(10)   # Alternative1: 11.2
    mytestX = testMOD()
    mytestX.testFunc(10)   # Original: 22
    
  3. 对类方法执行猴子修补。与第一种方法不同,它更改了类的任何实例的行为:

    class testMOD(object):
    def testFunc(self, variable):
    var = variable
    self.something = var + 12
    print('Original:', self.something)
    def alternativeFunc2(self, variable):
    var = variable
    self.something = var + 1.2
    print('Alternative2:', self.something)
    mytest2 = testMOD()
    mytest2.testFunc(10)   # Original: 22
    testMOD.testFunc = alternativeFunc2
    mytest2.testFunc(10)   # Alternative2: 11.2
    mytestX = testMOD()
    mytestX.testFunc(10)   # Alternative2: 11.2
    
  4. 创建一个继承自testMOD的类来重写该方法:

    class testMODNew(testMOD):
    def testFunc(self, variable):
    var = variable
    self.something = var + 1.2
    print('Alternative3:', self.something)
    mytest3 = testMODNew()
    mytest3.testFunc(10) # Alternative3: 11.2
    

你可以按如下方式修补此方法:

class TestMOD(object):
def testFunc(self, variable):
var = variable
self.something = var + 12
print(f'original {self.something}')

def alternativeFunc(self, variable):
var = variable
self.something = var + 1.2
print(f'alternative {self.something}')

if __name__ == '__main__':
test_original = TestMOD()
test_original.testFunc(12)
TestMOD.testFunc = alternativeFunc
test_alternate = TestMOD()
test_alternate.testFunc(12)

输出:

original 24
alternative 13.2

在 Python 中检查类继承以创建自己的自定义类:

from somemodule import TestMOD
class YourCustomClass(TestMOD):
# change the function
def test_func(self, variable):
#
#
your_class = YourCustomClass()
your_class.test_func(x)

这是一种黑客攻击,但您可以使用lambda函数:

mytest.testFunc = lambda *args, **kwargs: alternativeFunc(mytest, *args, **kwargs)

由于最初的问题要求一种在父类中调用函数的方法,然后也做一些额外的事情,我想我会指出简单地替换函数可能会有问题; 如果以任何方式修改父类(它所属的模块已更新(,则可能需要相应地修改代码。此外,他们可能不想重新创建原始函数只是为了在末尾添加一点。

我绝对同意创建一个从testMod继承的类是最好的选择,我只是建议从testMod调用函数,然后修改结果。

class testMOD(object):
def testFunc(self, variable):
var = variable
return var + 12

class testMODNew(testMOD):
def testFunc(self, variable):
return testMOD.testFunc(self,variable) - 10.8

mytest4 = testMODNew()
print('Alternative4:', mytest4.testFunc(10)) # Alternative4: 11.2

可以进行其他更改,例如,如果您希望具有该类的对象跟踪调用该方法的次数:

class testMODNew(testMOD):
__testFuncCount__ = 0
def testFunc(self, variable):
self.__testFuncCount__ += 1
return testMOD.testFunc(self,variable)

def getTestFuncCount(self):
return self.__testFuncCount__
mytest5 = testMODNew()
print('Original:',mytest5.testFunc(10)) #Original: 10
print('Original:',mytest5.testFunc(10)) #Original: 10
print('testFunc was called', mytest5.getTestFuncCount(), 'times.') 
#testFunc was called 2 times

最新更新