9 ответов:
пожалуйста, не делайте этого, как показано на рисунке. Вы код становится нечитаемым, когда вы monkeypatch экземпляр будет отличаться от класса.
вы не можете отлаживать monkeypatched код.
когда вы найдете ошибку в
bobyиprint type(boby), вы увидите ,что (а) это собака, но (б) по какой-то неясной причине она не лает правильно. Это просто кошмар. Не делай этого.пожалуйста, сделайте это вместо этого.
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!!можно использовать
bobyпеременной внутри функции, если вам нужно. Поскольку вы переопределяете метод только для этого одного объекта экземпляра, этот способ проще и имеет точно такой же эффект, как использованиеself.
вам нужно использовать 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!!
чтобы объяснить отличный ответ @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 модель данных.
Так как функции являются объектами первого класса в 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
Я нашел, что это самый точный ответ на исходный вопрос
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 и согласна с вещью " type (a)", но поскольку функции тоже имеют доступные атрибуты, я думаю, что это можно управлять следующим образом:
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
дорогой это не переопределение вы просто вызываете одну и ту же функцию дважды с объектом. В основном переопределение связано с несколькими классами. когда один и тот же метод подписи существует в разных классах, то какая функция вызывает это, решает объект, который вызывает это. Переопределение возможно в python, когда вы делаете более одного класса, записываете одни и те же функции и еще одну вещь, чтобы поделиться тем, что перегрузка не разрешена в python
Comments