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
有没有办法在Python中执行此操作?
答案 0 :(得分:11)
在方法内部分配self
只需将局部变量self
重新绑定到新对象。通常,对裸名称的赋值永远不会更改任何对象,它只是重新绑定左侧的名称以指向右侧的对象。
因此,您需要做的是修改对象self
以匹配对象self.o
指向的对象。只有当A
和Wrapper
都是新式类且没有一个定义__slots__
时,才有可能:
self.__class__ = self.o.__class__
self.__dict__ = self.o.__dict__
这将在CPython中有效,但我不确定其他Python实现。即使在CPython中,这样做也是一个糟糕的主意。
(请注意,代码最后一行中的is
条件仍为False
,但我认为这符合您的意图。)
答案 1 :(得分:4)
self
就好了,但这样做不会影响引用作为参数传递的任何位置(例如您的w
)。
考虑到情况(隐式传递self
),甚至不可能应用通常的黑客攻击(例如使用单元素列表和变异x[0]
)。即使这样的技巧可行(或者如果有一个更加模糊的黑客可以这样做),他们也会非常沮丧。它违背了Python程序员习惯的一切。只需让Wrapper
对象按照替换它(即将所有内容转发到self.o
)。这不会使身份检查成功,但它是迄今为止最简单,最清洁,最易维护的解决方案。
注意:为了进行实验,有一个非标准且绝对不可移植的PyPy扩展可以执行此操作(替换对象完全):__pypy__.become
。不用说,使用它是非常不明智的。找到另一种解决方案。
答案 2 :(得分:0)
您已经覆盖了自己,但更改仅在 fun()中本地有效。我添加了几个打印输出来试试:
def fun(self, *args, **kwargs):
print self, self.o
self = self.o # here want to swap
print self, self.o
输出显示原始Wrapper和A in self和self.o,然后是A和traceback,因为self.o在A类中无效。
<__main__.Wrapper object at 0xb77be38c> <__main__.A object at 0xb77be34c>
<__main__.A object at 0xb77be34c>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/python-2803VQb.py", line 21, in <module>
print w.fun() # some operation after which I want to loose Wrapper
File "/tmp/python-2803VQb.py", line 8, in fun
print self, self.o
AttributeError: 'A' object has no attribute 'o'
改变自我和副作用是不好的。为什么不直接在调用代码中分配给w:
print w.fun() # some operation after which I want to loose Wrapper
w = a # Sure you will loose the Wrapper
print a is w # this goes False and I'd like True :)