有没有办法在Python中覆盖实例级别的类方法?例如:
class Dog: def bark(self): print "WOOF" boby = Dog() boby.bark() # WOOF # METHOD OVERRIDE boby.bark() # WoOoOoF!!
codelogic.. 149
是的,这是可能的:
class Dog: def bark(self): print "Woof" def new_bark(self): print "Woof Woof" foo = Dog() funcType = type(Dog.bark) # "Woof" foo.bark() # replace bark with new_bark for this object only foo.bark = funcType(new_bark, foo, Dog) foo.bark() # "Woof Woof"
我想这不适用于Python 3.我得到一个"TypeError:function()参数1必须是代码,而不是函数"错误.有关Python 3的任何建议吗? (12认同)
请解释一下这是做什么的,特别是`funcType`做什么以及为什么有必要. (10认同)
我认为通过使用`funcType = types.MethodType`(导入`types`之后)而不是`funcType = type(Dog.bark)`,可以使这更简单,更明确. (2认同)
您还可以在函数上调用`__get__`将其绑定到实例。 (2认同)
Harshal Dhum.. 31
您需要在类型模块中使用MethodType.MethodType的目的是覆盖实例级方法(以便在覆盖方法中可以使用self).
见下面的例子.
import types class Dog: def bark(self): print "WOOF" boby = Dog() boby.bark() # WOOF def _bark(self): print "WoOoOoF!!" boby.bark = types.MethodType(_bark, boby) boby.bark() # WoOoOoF!!
nosklo.. 25
class Dog: def bark(self): print "WOOF" boby = Dog() boby.bark() # WOOF # METHOD OVERRIDE def new_bark(): print "WoOoOoF!!" boby.bark = new_bark boby.bark() # WoOoOoF!!
boby
如果需要,可以在函数内部使用变量.由于您仅为此一个实例对象覆盖该方法,因此这种方式更简单,并且与使用具有完全相同的效果self
.
是的,这是可能的:
class Dog: def bark(self): print "Woof" def new_bark(self): print "Woof Woof" foo = Dog() funcType = type(Dog.bark) # "Woof" foo.bark() # replace bark with new_bark for this object only foo.bark = funcType(new_bark, foo, Dog) foo.bark() # "Woof Woof"
您需要在类型模块中使用MethodType.MethodType的目的是覆盖实例级方法(以便在覆盖方法中可以使用self).
见下面的例子.
import types class Dog: def bark(self): print "WOOF" boby = Dog() boby.bark() # WOOF def _bark(self): print "WoOoOoF!!" boby.bark = types.MethodType(_bark, boby) boby.bark() # WoOoOoF!!
class Dog: def bark(self): print "WOOF" boby = Dog() boby.bark() # WOOF # METHOD OVERRIDE def new_bark(): print "WoOoOoF!!" boby.bark = new_bark boby.bark() # WoOoOoF!!
boby
如果需要,可以在函数内部使用变量.由于您仅为此一个实例对象覆盖该方法,因此这种方式更简单,并且与使用具有完全相同的效果self
.
为了解释@ codelogic的优秀答案,我提出了一种更明确的方法.这是一种技术,.
当您将类方法作为实例属性访问时,操作员会彻底绑定类方法,除了您的方法实际上是在类之外定义的函数.
使用@ codelogic的代码,唯一的区别在于方法的绑定方式.我使用的事实是函数和方法是Python 中的非数据描述符,并调用该__get__
方法.请特别注意原始和替换都具有相同的签名,这意味着您可以将替换作为完整的类方法编写,通过访问所有实例属性self
.
class Dog: def bark(self): print "Woof" def new_bark(self): print "Woof Woof" foo = Dog() # "Woof" foo.bark() # replace bark with new_bark for this object only foo.bark = new_bark.__get__(foo, Dog) foo.bark() # "Woof Woof"
通过将绑定方法分配给实例属性,您已创建了几乎完全覆盖方法的模拟.缺少一个方便的功能是访问no-arg版本super
,因为您不在类定义中.另一件事是__name__
绑定方法的属性不会像它在类定义中那样采用它覆盖的函数的名称,但您仍然可以手动设置它.第三个区别是你的手动绑定方法是一个普通的属性引用,恰好是一个函数.该.
运营商不只是获取该引用.另一方面,当从实例调用常规方法时,绑定过程每次都会创建一个新的绑定方法.
顺便说一句,这种方法的唯一原因是实例属性覆盖非数据描述符.数据描述符有__set__
方法,哪种方法(幸运的是)不这样做.类中的数据描述符实际上优先于任何实例属性.这就是您可以分配给属性的原因:__set__
当您尝试进行分配时,会调用它们的方法.我个人喜欢更进一步,隐藏实例中底层属性的实际值,__dict__
正常情况下它无法访问,因为属性会影响它.
你还应该记住,这对于魔术(双下划线)方法来说毫无意义.魔术方法当然可以通过这种方式被覆盖,但使用它们的操作只能查看类型.例如,您可以__contains__
在实例中设置特殊内容,但调用x in instance
会忽略它并使用type(instance).__contains__(instance, x)
.这适用于Python 数据模型中指定的所有魔术方法.
请不要如图所示这样做.当您将实例monkeypatch与该类不同时,您的代码将变得不可读.
你无法调试monkeypatched代码.
当你发现中的错误boby
和print type(boby)
,你会看到(一)它是一只狗,但(b)对于一些模糊的原因,它不正确地吠叫.这是一场噩梦.不要做.
请改为做.
class Dog: def bark(self): print "WOOF" class BobyDog( Dog ): def bark( self ): print "WoOoOoF!!" otherDog= Dog() otherDog.bark() # WOOF boby = BobyDog() boby.bark() # WoOoOoF!!