是否有可能覆盖“self”以指向python中self.method中的另一个对象?

时间:2011-10-29 17:26:04

标签: python python-c-api

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中执行此操作?

3 个答案:

答案 0 :(得分:11)

在方法内部分配self只需将局部变量self重新绑定到新对象。通常,对裸名称的赋值永远不会更改任何对象,它只是重新绑定左侧的名称以指向右侧的对象。

因此,您需要做的是修改对象self以匹配对象self.o指向的对象。只有当AWrapper都是新式类且没有一个定义__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 :)