是否可以修改单个实例的方法实现而不影响同类的其他实例?

37 投票
6 回答
46351 浏览
提问于 2025-04-15 15:30

我对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的初始化方法:

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

但我得到了以下错误信息:

showyImp() 需要一个参数(给了0个)

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

有什么线索吗? :)

6 个回答

10

如果你需要为一个特殊的方法做一些处理(在新的类中——也就是你应该一直使用的类型,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.instancemethod 完全没用。另一方面……:

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

……为这个情况和其他所有情况分配一个新类效果很好。顺便说一下,正如我希望你能明白的,一旦你对某个实例做了这个处理,你就可以在它的 x.__class__ 上添加更多的方法和其他类属性,只会影响到这个特定的实例!

31

这个回答已经过时了;下面的回答适用于现代的Python

关于Python的属性和方法,你想知道的一切。

是的,这个回答有点间接,但它展示了许多技巧,并解释了一些更复杂的细节和“魔法”。

如果你想要一个“更直接”的回答,可以看看Python的new模块。特别是,看看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
66

从Python 2.6开始,你应该使用types模块里的MethodType类:

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__()

撰写回答