我正在尝试替换类中定义的函数,以便在不更改实际代码的情况下修改其函数(如在内部工作中(。 我以前从未这样做过,因此在更换它时遇到了一些问题。
更改代码将让我访问 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(: 我利用函数在 Python 中是描述符的事实,这样我就可以在
AlternativeFunc
上使用__get__
方法获取它作为实例mytest
的方法,并覆盖实例mytest
的testFunc
方法(不覆盖类方法(: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(:这次,我使用比第一个解决方案更具可读性的
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
对类方法执行猴子修补。与第一种方法不同,它更改了类的任何实例的行为:
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
创建一个继承自
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