Подтвердить что ты не робот

Переопределить метод на уровне экземпляра

Есть ли способ в Python переопределить метод класса на уровне экземпляра? Например:

class Dog:
    def bark(self):
        print "WOOF"

boby = Dog()
boby.bark() # WOOF
# METHOD OVERRIDE
boby.bark() # WoOoOoF!!
4b9b3361

Ответ 1

Пожалуйста, не делайте этого, как показано. Вы код становится нечитаемым, когда вы monkeypatch экземпляр отличается от класса.

Вы не можете отлаживать файл с обеими ключами.

Когда вы обнаружите ошибку в boby и print type(boby), вы увидите, что (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!!

Ответ 2

Да, возможно:

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"

Ответ 3

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.

Ответ 4

Вам нужно использовать 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!!

Ответ 5

Чтобы объяснить @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 .

Ответ 6

Поскольку функции являются объектами первого класса в 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

Ответ 7

Я нашел, что это самый точный ответ на исходный вопрос

fooobar.com/questions/101616/...

import a

def _new_print_message(message):
    print "NEW:", message

a.print_message = _new_print_message

import b
b.execute()

Ответ 8

Хотя мне понравилась идея наследования от S. Lott и согласна с темой типа (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

Ответ 9

Дорогой, это не переопределение, вы просто вызываете одну и ту же функцию дважды с объектом. В основном переопределение связано с более чем одним классом. когда такой же метод подписи существует в разных классах, то какая функция вы вызываете, это определяет объект, который вызывает это. Переопределение возможно в python, когда вы делаете несколько классов, записываете одни и те же функции, и еще одно - делиться тем, что перегрузка не допускается в python