在实例级重写一个方法

有没有在Python的方式来重写实例级的类方法? 例如:

class Dog: def bark(self): print "WOOF" boby = Dog() boby.bark() # WOOF # METHOD OVERRIDE boby.bark() # WoOoOoF!! 

请不要这样做,如图所示。 当您将一个实例与类相区别时,您的代码变得不可读。

你不能debuggingmonkeypatched的代码。

当你发现一个在bobyprint type(boby)的bug时,你会发现(a)它是一只狗,但是(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!! 

是的,这是可能的:

 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" 
 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!! 

如果需要,你可以在函数里面使用bobyvariables。 由于您只是针对这个实例对象重写方法,所以这种方法更简单,并且与使用self效果完全相同。

您需要使用types模块中的MethodType。 MethodType的用途是覆盖实例级别的方法(这样自我可以覆盖的方法)。

看下面的例子。

 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!! 

由于函数是Python中的第一类对象,因此您可以在初始化类对象时传递它们,或者在给定的类实例中随时覆盖它们:

 class Dog: def __init__(self, barkmethod=None): self.bark=self.barkp if barkmethod: self.bark=barkmethod def barkp(self): print "woof" d=Dog() print "calling original bark" d.bark() def barknew(): print "wooOOOoof" d1=Dog(barknew) print "calling the new bark" d1.bark() def barknew1(): print "nowoof" d1.bark=barknew1 print "calling another new" d1.bark() 

结果是

 calling original bark woof calling the new bark wooOOOoof calling another new nowoof 

为了解释@ codelogic的优秀答案,我提出了一个更明确的方法。 这是同样的技巧. 除非你的方法实际上是一个在类之外定义的函数,否则当你作为一个实例属性访问它时,运算符会彻底地绑定一个类方法。

使用@ codelogic的代码,唯一的区别是方法是如何绑定的。 我正在使用的事实是函数和方法是Python中的非数据描述符 ,并调用__get__方法。 请特别注意,原始文件和replace文件都具有相同的签名,这意味着您可以将replace文件写为完整的类方法,通过self访问所有实例属性。

上课狗:
     def bark(self):
        打印“Woof”

 def new_bark(self):
    打印“Woof Woof”

 foo =狗()

 #“Woof”
 foo.bark()

 #只用new_barkreplace这个对象的树皮
 foo.bark = new_bark .__ get __(foo,Dog)

 foo.bark()
 #“Woof Woof”

通过将绑定方法分配给实例属性,您已经创build了覆盖方法的几乎完整的模拟。 缺less的一个便利function是访问super的no-arg版本,因为您不在类定义中。 另一件事是你绑定的方法的__name__属性不会像它在类定义中那样取得它所覆盖的函数的名字,但是你仍然可以手动设置它。 第三个区别是你的手动绑定的方法是一个普通的属性引用,恰好是一个函数。 的. 运算符只会获取该引用。 另一方面,当从一个实例调用常规方法时,绑定过程每次创build一个新的绑定方法。

顺便说一句,唯一的原因是实例属性会覆盖非数据描述符。 数据描述符有__set__方法,哪些方法(幸运的是你)不。 类中的数据描述符实际上优先于任何实例属性。 这就是为什么你可以分配给一个属性:当你尝试做一个任务时,他们的__set__方法被调用。 我个人喜欢更进一步,隐藏实例的__dict__中的底层属性的实际值,通过正常手段无法访问,正是因为属性给它遮蔽。

你也应该记住,这对于魔术(双下划线)方法来说是毫无意义的。 魔术方法当然可以用这种方式重写,但是使用它们的操作只能看types。 例如,您可以将__contains__设置为您的实例中特殊的内容,但x in instance调用x in instance将忽略该内容,并使用type(instance).__contains__(instance, x) 。 这适用于在Python 数据模型中指定的所有魔术方法。

我发现这是对原始问题最准确的答案

https://stackoverflow.com/a/10829381/7640677

 import a def _new_print_message(message): print "NEW:", message a.print_message = _new_print_message import b b.execute() 

虽然我喜欢S. Lott的inheritance思想,并且同意“types(a)”的东西,但是因为函数也具有可访问的属性,我认为它可以这样pipe理:

 class Dog: def __init__(self, barkmethod=None): self.bark=self.barkp if barkmethod: self.bark=barkmethod def barkp(self): """original bark""" print "woof" d=Dog() print "calling original bark" d.bark() print "that was %s\n" % d.bark.__doc__ def barknew(): """a new type of bark""" print "wooOOOoof" d1=Dog(barknew) print "calling the new bark" d1.bark() print "that was %s\n" % d1.bark.__doc__ def barknew1(): """another type of new bark""" print "nowoof" d1.bark=barknew1 print "another new" d1.bark() print "that was %s\n" % d1.bark.__doc__ 

输出是:

 calling original bark woof that was original bark calling the new bark wooOOOoof that was a new type of bark another new nowoof that was another type of new bark 

亲爱的,这不是重写你只是调用与对象两次相同的function。 基本上,压倒一切与一个以上的课程有关。 当相同的签名方法存在于不同的类中时,你调用的函数决定了调用这个函数的对象。 在python中重写是可能的,当你使多个类写入相同的function和一个更多的东西分享,不允许在python