is it possible to overwrite “self” to point to another object inside self.method in python?

走远了吗. 提交于 2020-07-18 20:18:50

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!