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

Можно ли изменить реализацию метода экземпляра без изменения всех других экземпляров одного и того же класса?

Я не очень хорошо знаю python (никогда не использовал его раньше: D), но я не могу найти что-либо в Интернете. Возможно, я просто не ответил на правильный вопрос, но здесь я иду:

Я хочу изменить реализацию экземпляра определенного метода. Когда я искал ее для поиска, я обнаружил, что вы можете это сделать, но она меняет реализацию для всех других экземпляров одного и того же класса, например:

def showyImp(self):
    print self.y

class Foo:
    def __init__(self):
        self.x = "x = 25"
        self.y = "y = 4"

    def showx(self):
        print self.x

    def showy(self):
         print "y = woohoo"

class Bar:
    def __init__(self):
        Foo.showy = showyImp
        self.foo = Foo()

    def show(self):
        self.foo.showx()
        self.foo.showy()

if __name__ == '__main__':
    b = Bar()
    b.show()
    f = Foo()
    f.showx()
    f.showy()

Это не работает должным образом, потому что вывод следующий:

x = 25

y = 4

x = 25

y = 4

И я хочу, чтобы это было:

x = 25

y = 4

x = 25

y = woohoo

Я попытался изменить метод Bar init следующим образом:

def __init__(self):
    self.foo = Foo()
    self.foo.showy = showyImp

Но я получаю следующее сообщение об ошибке:

showyImp() принимает ровно 1 аргумент (задано 0)

Так что да... Я попытался использовать setattr(), но похоже, что он такой же, как self.foo.showy = showyImp.

Любая подсказка?:)

4b9b3361

Ответ 1

Все, что вы хотели знать об атрибутах и методах Python.

Да, это косвенный ответ, но он демонстрирует ряд приемов и объясняет некоторые более сложные детали и "магию".

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

import new
class Z(object):
  pass
z = Z() 
def method(self):
  return self
z.q = new.instancemethod(method, z, None)
z is z.q()  # true

Ответ 2

Начиная с Python 2.6, вы должны использовать класс types MethodType class:

from types import MethodType

class A(object):
    def m(self):
        print 'aaa'

a = A()

def new_m(self):
    print 'bbb'

a.m = MethodType(new_m, a)

Однако, как заметил другой ответ, это не будет работать для "магических" методов классов нового стиля, таких как __str__().

Ответ 3

Если вам когда-либо понадобится сделать это для специального метода (который для класса нового стиля - именно то, что вы всегда должны использовать и единственный вид в Python 3 - просматривается на классе, а не экземпляр), вы можете просто создать класс для каждого экземпляра, например...:

self.foo = Foo()
meths = {'__str__': lambda self: 'peekaboo!'}
self.foo.__class__ = type('yFoo', (Foo,), meths)

Изменить: меня попросили разъяснить преимущества этого подхода в отношении new.instancemethod...:

>>> class X(object): 
...   def __str__(self): return 'baah'
... 
>>> x=X()
>>> y=X()
>>> print x, y
baah baah
>>> x.__str__ = new.instancemethod(lambda self: 'boo!', x)
>>> print x, y
baah baah

Как вы можете видеть, в этом случае метод new.instance абсолютно бесполезен. Ото...

>>> x.__class__=type('X',(X,),{'__str__':lambda self:'boo!'})
>>> print x, y
boo! baah

... присвоение нового класса отлично подходит для этого случая и для всех остальных. BTW, как я надеюсь, ясно, как только вы сделали это с данным экземпляром, вы можете позже добавить к его x.__class__ еще один метод и другие атрибуты класса и на самом деле повлиять только на один экземпляр!

Ответ 4

Если вы привязываетесь к экземпляру, вы не должны включать аргумент self:

>>> class Foo(object):
...     pass
... 
>>> def donothing():
...     pass
... 
>>> f = Foo()
>>> f.x = donothing
>>> f.x()
>>> 

Вам нужен аргумент self, если вы привязываетесь к классу:

>>> def class_donothing(self):
...     pass
... 
>>> foo.y = class_donothing
>>> f.y()
>>> 

Ответ 5

Не делай этого.

Изменение одного метода экземпляра просто неверно.

Вот правила OO Design.

  • Избегайте магии.

  • Если вы не можете использовать наследование, используйте делегирование.

Это означает, что каждый раз, когда вы думаете, что вам нужно что-то волшебное, вы должны были написать "обертку" или "Фасад" вокруг объекта, чтобы добавить нужные вам функции.

Просто напишите обертку.

Ответ 6

Ваш пример - извращенный и сложный, и я не совсем понимаю, что он должен делать с вашим вопросом. Не стесняйтесь уточнять, если хотите.

Однако, довольно легко сделать то, что вы хотите сделать, предполагая, что я правильно читаю ваш вопрос.

class Foo(object):
    def bar(self):
        print('bar')

def baz():
    print('baz')

В интерпретаторе...

>>> f = Foo()
>>> f.bar()
bar
>>> f.bar = baz
>>> f.bar()
baz
>>> g = Foo()
>>> g.bar()
bar
>>> f.bar()
baz