问题
class Wrapper(object):
def __init__(self, o):
# get wrapped object and do something with it
self.o = o
def fun(self, *args, **kwargs):
self = self.o # here want to swap
# or some low level C api like
# some_assign(self, self.o)
# so that it swaps id() mem addr to self.o
return self.fun(*args, **kwargs) # and now it's class A
class A(object):
def fun(self):
return 'A.fun'
a = A()
w = Wrapper(a)
print type(w) # wrapper
print w.fun() # some operation after which I want to loose Wrapper
print a is w # this goes False and I'd like True :)
# so that this is the original A() object
Is there any way to do this in Python?
回答1:
Assigning to self
inside a method simply rebinds the local variable self
to the new object. Generally, an assignment to a bare name never changes any objects, it just rebinds the name on the left-hand side to point to the object on the right-hand side.
So what you would need to do is modify the object self
points to to match the object self.o
points to. This is only possible if both A
and Wrapper
are new-style classes and none of them defines __slots__
:
self.__class__ = self.o.__class__
self.__dict__ = self.o.__dict__
This will work in CPython, but I'm not sure about the other Python implementation. And even in CPython, it's a terrible idea to do this.
(Note that the is
condition in the last line of your code will still be False
, but I think this does what you intend.)
回答2:
No, you can't. This would require pass by reference. You can change the local variable (more precisely, the parameter) self
just fine, but doing that does not influence whatever location the reference passed as argument came from (such as your w
).
And given the circumstances (implicitly passed self
), it's not even possible to apply the usual hacks (such as using a single-element list and mutate x[0]
). Even if such tricks would work (or if there's an even more obscure hack that can do this), they'd be highly discouraged. It goes against everything Python programmers are used to. Just make the Wrapper
object act as if it was replaces (i.e. forward everything to self.o
). That won't make identity checks succeed, but it's by far the simplest, cleanest and most maintainable solution.
Note: For the sake of experimenting, there is a nonstandard and absolutely nonportable PyPy extension which can do this (replacing an object completely): __pypy__.become. Needless to say, it'd be extremely ill-advised to use it. Find another solution.
来源:https://stackoverflow.com/questions/7940470/is-it-possible-to-overwrite-self-to-point-to-another-object-inside-self-method