是否可以在不更改同一类的所有其他实例的情况下更改实例的方法实现?

问题描述 投票:18回答:6

我不太了解python(之前从未使用过它:D),但我似乎无法在网上找到任何东西。也许我只是没有谷歌正确的问题,但在这里我去:

我想更改实例的特定方法的实现。当我用Google搜索它时,我发现你可以这样做,但它改变了同一个类的所有其他实例的实现,例如:

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 =呜呼

我尝试用这个改变Bar的init方法:

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

但是我收到以下错误消息:

showyImp()只需要1个参数(给定0)

所以是的...我尝试使用setattr(),但看起来它和self.foo.showy = showyImp一样。

任何线索? :)

python
6个回答
22
投票

关于Python Attributes and Methods你想知道的一切。

是的,这是一个间接的答案,但它展示了许多技术并解释了一些更复杂的细节和“魔力”。

要获得“更直接”的答案,请考虑python's new module。特别是,请查看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

23
投票

从Python 2.6开始,你应该使用qazxsw poi模块qazxsw poi类:

types

然而,正如另一个答案所指出的,这对于新式课程的“魔术”方法不起作用,例如MethodType


8
投票

如果你需要为一个特殊的方法(对于一个新式的类 - 这是你应该一直使用的,也是Python 3中唯一的类 - 在类中查找,而不是实例) ,你可以只创建一个实例类,例如...:

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)

编辑:我被要求澄清这种方法的优点,以及new.instancemethod ......:

__str__()

正如您所看到的,new.instance方法在这种情况下完全没用。 OTOH ...:

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

......分配一个新课程对于这个案例和其他所有人都很有用。顺便说一下,正如我希望的那样,一旦你对一个给定的实例做了这个,你可以在以后为它的>>> 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 添加更多的方法和其他类属性,并且本质上只影响那个实例!


5
投票

如果您绑定到实例,则不应包含self参数:

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

如果你绑定到一个类,你确实需要self参数:

x.__class__

0
投票

你的例子有点扭曲和复杂,我不太明白它与你的问题有什么关系。如果你愿意,请随意澄清。

但是,假设我正在阅读你的问题,你很容易做你想做的事情。

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

在口译员......

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

0
投票

不要这样做。

改变一个实例的方法是错误的。

以下是OO设计的规则。

  1. 避免魔法。
  2. 如果您不能使用继承,请使用委托。

这意味着每次你认为你需要一些魔法时,你应该在对象周围写一个“包装器”或Facade来添加你想要的功能。

只需写一个包装器。

© www.soinside.com 2019 - 2024. All rights reserved.