我正在尝试将classmethods动态添加到Python 2.7类中。我还在3.5.1中测试了同样的问题,同样的事情发生了。这个目的是用于单元测试模拟。这里的答案How to add a classmethod in Python dynamically似乎是相关的,但是当继承也发挥作用时它们似乎会破裂。当我使用我的mock时,cls绑定总是得到父类,而不是我称之为classmethod的类。为什么会发生这种情况?我如何实现嘲弄类方法并在cls中获得正确的类?
class Parent(object):
@classmethod
def clm(cls):
return 'Orig:' + cls.__name__
class Child(Parent):
pass
print 'Parent:', Parent.clm()
# Parent: Orig:Parent as expected
print 'Child:', Child.clm()
# Child: Orig:Child as expected as well, because cls is Child
def mock_clm(cls):
return 'Ovr:' + cls.original_clm()
# Save the original and replace with mock function
Parent.original_clm = Parent.clm
Parent.clm = classmethod(mock_clm)
print 'Parent:', Parent.clm()
# Parent: Ovr:Orig:Parent as expected, our mock function is called
print 'Child:', Child.clm()
# Child: Ovr:Orig:Parent! What I wanted here is to get Ovr:Orig:Child
# but for some reason the classmethod cls binding breaks and returns
# Parent instead
# Note how original_clm doesn't bind as I expected as well
print 'Parent:', Parent.original_clm()
print 'Child:', Child.original_clm()
我尝试了各种其他的模拟方法,比如使用mock.patch,在父类上使用setattr并将装饰器添加到函数中而不是在assigment上使用它,都具有相同的效果。这是使用mock的示例代码,它产生相同的结果:
import mock
with mock.patch('__main__.Parent.clm', classmethod(mock_clm)):
print 'Parent:', Parent.clm()
# Parent: Ovr:Orig:Parent
print 'Child:', Child.clm()
# Child: Ovr:Orig:Parent