Python:替换模块 class 中的函数
Python: replacing a function within a class of a module
我正在尝试替换 class 中定义的函数,以便在不更改实际代码的情况下修改其功能(如在内部工作中)。
我以前从未这样做过,因此在替换它时遇到了一些问题。
更改代码将使我能够访问我的 Python 库中的包,这不是一个很好的选择。
例如,如果模块名为 testMOD,
class testMOD(object):
def testFunc(self, variable):
var = variable
self.something = var + 12
然后我将导入testMOD,定义一个class (mytest = testMOD()),并访问class中定义的函数,testFunc,并将其更改为已经定义的函数。
例如,
from somemodule import testMOD
mytest = testMOD()
def alternativeFunc(self, variable):
var = variable
self.something = var + 1.2
# A problem here
mytest.testFunc = alternativeFunc
如您所见,如果我只是用我定义的函数手动覆盖(?)class 中的函数,它将无法正常工作。
它没有给出任何语法错误,但是,问题是被替换的函数认为 'self' 是该函数的另一个变量,并说它需要 [=33= 的另一个参数] 变量(我想这不是一个好名字)。
我想让替换函数与被替换函数完全一样,但要有额外的代码或一些小的修改。但是,'self' 几乎无法正常工作,因为它应该在 class.
中
有没有办法正确实现定义的函数来替换导入的函数class?
在 Python 中检查 class 继承以创建您自己的自定义 class:
from somemodule import TestMOD
class YourCustomClass(TestMOD):
# change the function
def test_func(self, variable):
#
#
your_class = YourCustomClass()
your_class.test_func(x)
你可以monkey patch这个方法如下:
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
我建议 4 个解决方案,从最差到最好(恕我直言),当然这也取决于您的具体限制:
替换实例方法(一):我在Python中利用函数是描述符,这样就可以在[=15=上使用__get__
方法] 将其作为实例 mytest
的方法获取并覆盖实例 mytest
的 testFunc
方法(不覆盖 class 方法):
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
替换实例方法(二):这次我用的是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方法进行猴子修补。与第一种方法不同,它改变了 class 的任何实例的行为:
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来覆盖方法:
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
这是一种 hack,但您可以使用 lambda 函数:
mytest.testFunc = lambda *args, **kwargs: alternativeFunc(mytest, *args, **kwargs)
由于最初的问题要求一种方法来调用父函数 class 然后再做一些额外的事情,我想我要指出的是,简单地替换函数可能会有问题;如果父 class 以任何方式被修改(它所属的模块被更新),那么您可能必须相应地修改代码。此外,他们可能不想为了在末尾添加一点而重新创建原始函数。
我绝对同意创建一个从 testMod 继承的 class 是最好的选择,我只是建议从 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 的对象跟踪调用该方法的次数:
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
我正在尝试替换 class 中定义的函数,以便在不更改实际代码的情况下修改其功能(如在内部工作中)。 我以前从未这样做过,因此在替换它时遇到了一些问题。
更改代码将使我能够访问我的 Python 库中的包,这不是一个很好的选择。
例如,如果模块名为 testMOD,
class testMOD(object):
def testFunc(self, variable):
var = variable
self.something = var + 12
然后我将导入testMOD,定义一个class (mytest = testMOD()),并访问class中定义的函数,testFunc,并将其更改为已经定义的函数。
例如,
from somemodule import testMOD
mytest = testMOD()
def alternativeFunc(self, variable):
var = variable
self.something = var + 1.2
# A problem here
mytest.testFunc = alternativeFunc
如您所见,如果我只是用我定义的函数手动覆盖(?)class 中的函数,它将无法正常工作。
它没有给出任何语法错误,但是,问题是被替换的函数认为 'self' 是该函数的另一个变量,并说它需要 [=33= 的另一个参数] 变量(我想这不是一个好名字)。
我想让替换函数与被替换函数完全一样,但要有额外的代码或一些小的修改。但是,'self' 几乎无法正常工作,因为它应该在 class.
中有没有办法正确实现定义的函数来替换导入的函数class?
在 Python 中检查 class 继承以创建您自己的自定义 class:
from somemodule import TestMOD
class YourCustomClass(TestMOD):
# change the function
def test_func(self, variable):
#
#
your_class = YourCustomClass()
your_class.test_func(x)
你可以monkey patch这个方法如下:
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
我建议 4 个解决方案,从最差到最好(恕我直言),当然这也取决于您的具体限制:
替换实例方法(一):我在Python中利用函数是描述符,这样就可以在[=15=上使用
__get__
方法] 将其作为实例mytest
的方法获取并覆盖实例mytest
的testFunc
方法(不覆盖 class 方法):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
替换实例方法(二):这次我用的是
可读性更好一点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方法进行猴子修补。与第一种方法不同,它改变了 class 的任何实例的行为:
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来覆盖方法: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
这是一种 hack,但您可以使用 lambda 函数:
mytest.testFunc = lambda *args, **kwargs: alternativeFunc(mytest, *args, **kwargs)
由于最初的问题要求一种方法来调用父函数 class 然后再做一些额外的事情,我想我要指出的是,简单地替换函数可能会有问题;如果父 class 以任何方式被修改(它所属的模块被更新),那么您可能必须相应地修改代码。此外,他们可能不想为了在末尾添加一点而重新创建原始函数。
我绝对同意创建一个从 testMod 继承的 class 是最好的选择,我只是建议从 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 的对象跟踪调用该方法的次数:
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