【问题标题】:is it possible to overwrite "self" to point to another object inside self.method in python?是否可以覆盖“self”以指向python中self.method中的另一个对象?
【发布时间】:2011-10-29 17:26:03
【问题描述】:
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 中做到这一点?

【问题讨论】:

  • @outis 是的,得到:main.Wrapper'>, A.fun, False
  • 可以像这样做一些奇怪的事情。我不确定我是否应该告诉你怎么做,因为人们实际上可能会开始做这样可怕的事情。
  • 如果我没听错的话,你想要一个与 Smalltalk 的 '#become:' 等效的东西吗?谷歌搜索给了我:wargle.blogspot.com/2009/07/smalltalks-become-in-python.html。 (也就是说代码给我灌输了暴力冲动。)
  • @Inerdia:该代码不仅具有伪装性,甚至不能用于此目的 - is 仍将是 False
  • 你想完成什么?

标签: python python-c-api


【解决方案1】:

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

所以你需要做的是修改对象self指向以匹配对象self.o指向。这只有在AWrapper 都是新式类并且它们都没有定义__slots__ 时才有可能:

self.__class__ = self.o.__class__
self.__dict__ = self.o.__dict__

这将在 CPython 中工作,但我不确定其他 Python 实现。即使在 CPython 中,这样做也是一个糟糕的主意。

(请注意,代码最后一行中的is 条件仍然是False,但我认为这符合您的意图。)

【讨论】:

  • 啊,这就是你说的把戏。 +1 纯粹的聪明,尽管它非常可怕。
  • 在许多极端情况下会惨遭失败,例如,如果类派生自 object 以外的 C 类型。
【解决方案2】:

不,你不能。这需要通过引用传递。您可以更改局部变量(更准确地说是参数)self,但这样做不会影响作为参数传递的引用来自任何位置(例如您的 w)。

鉴于这种情况(隐式传递self),甚至不可能应用通常的技巧(例如使用单元素列表和变异x[0])。即使这样的技巧会奏效(或者如果有一个更晦涩难懂的黑客可以做到这一点),他们也会受到高度劝阻。它违背了 Python 程序员所习惯的一切。只需让Wrapper 对象表现得好像 它被替换了(即转发一切self.o)。这不会使身份检查成功,但它是迄今为止最简单、最干净和最可维护的解决方案。

注意:为了试验,有一个非标准且绝对不可移植的 PyPy 扩展可以做到这一点(完全替换一个对象):__pypy__.become。不用说,使用它是非常不明智的。寻找其他解决方案。

【讨论】:

  • 即使在 CPython 中也是可能的,所以“你不能”似乎是错误的。不过,这是一个糟糕的主意。
  • @SvenMarnach:嗯,我对解释器一无所知(当然,除了编写 C 代码),而且我已经非常熟悉这些 hack。不过,我不能完全排除它,所以我添加了一个条款来涵盖它(甚至在你的评论之前)。
  • 添加了我自己的答案来解释如何。老实说,它并没有完全按照 OP 的要求进行。 +1 链接到__pypy__.become,很有趣。
猜你喜欢
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
  • 2019-08-21
  • 2019-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多