I do not know python very much (never used it before :D), but I can't seem to find anything online. Maybe I just didn't google the right question, but here I go:
I want to change an instance's implementation of a specific method. When I googled for it, I found you could do it, but it changes the implementation for all other instances of the same class, for example:
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()
This does not work as expected, because the output is the following:
x = 25
y = 4
x = 25
y = 4
And I want it to be:
x = 25
y = 4
x = 25
y = woohoo
I tried to change Bar's init method with this:
def __init__(self):
self.foo = Foo()
self.foo.showy = showyIm开发者_StackOverflow中文版p
But I get the following error message:
showyImp() takes exactly 1 argument (0 given)
So yeah... I tried using setattr()
, but seems like it's the same as self.foo.showy = showyImp
.
Any clue? :)
Since Python 2.6, you should use the types
module's 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)
As another answer pointed out, however, this will not work for 'magic' methods of new-style classes, such as __str__()
.
This answer is outdated; the answer below works with modern Python
Everything you wanted to know about Python Attributes and Methods.
Yes, this is an indirect answer, but it demonstrates a number of techniques and explains some of the more intricate details and "magic".
For a "more direct" answer, consider python's new module. In particular, look at the instancemethod function which allows "binding" a method to an instance -- in this case, that would allow you to use "self" in the method.
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
If you ever need to do it for a special method (which, for a new-style class -- which is what you should always be using and the only kind in Python 3 -- is looked up on the class, not the instance), you can just make a per-instance class, e.g....:
self.foo = Foo()
meths = {'__str__': lambda self: 'peekaboo!'}
self.foo.__class__ = type('yFoo', (Foo,), meths)
Edit: I've been asked to clarify the advantages of this approach wrt 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
As you can see, the new.instancemethod is totally useless in this case. OTOH...:
>>> x.__class__=type('X',(X,),{'__str__':lambda self:'boo!'})
>>> print x, y
boo! baah
...assigning a new class works great for this case and every other. BTW, as I hope is clear, once you've done this to a given instance you can then later add more method and other class attributes to its x.__class__
and intrinsically affect only that one instance!
If you're binding to the instance, you shouldn't include the self argument:
>>> class Foo(object):
... pass
...
>>> def donothing():
... pass
...
>>> f = Foo()
>>> f.x = donothing
>>> f.x()
>>>
You do need the self argument if you're binding to a class though:
>>> def class_donothing(self):
... pass
...
>>> foo.y = class_donothing
>>> f.y()
>>>
Your example is kind of twisted and complex, and I don't quite see what it has to do with your question. Feel free to clarify if you like.
However, it's pretty easy to do what you're looking to do, assuming I'm reading your question right.
class Foo(object):
def bar(self):
print('bar')
def baz():
print('baz')
In an interpreter ...
>>> f = Foo()
>>> f.bar()
bar
>>> f.bar = baz
>>> f.bar()
baz
>>> g = Foo()
>>> g.bar()
bar
>>> f.bar()
baz
Do Not Do This.
Changing one instance's methods is just wrong.
Here are the rules of OO Design.
Avoid Magic.
If you can't use inheritance, use delegation.
That means that every time you think you need something magic, you should have been writing a "wrapper" or Facade around the object to add the features you want.
Just write a wrapper.
精彩评论