Python:解除对weakproxy的引用

Python:解除对weakproxy的引用,python,weak-references,Python,Weak References,有没有办法从指向原始对象的弱路径获取原始对象?例如,weakref.proxy()是否与相反 一个简化示例(python2.7): 我需要从我的列表中获取唯一其他成员的列表。我喜欢这样的工作方式 要使用设置: unique_others = {x.other for x in my_list} 不幸的是,这会抛出TypeError:unhabable类型:“weakproxy” 我已设法以一种紧迫的方式(缓慢而肮脏)解决了具体问题: 但标题中指出的一般问题仍然存在。 如果我只控制了我的列表,而

有没有办法从指向原始对象的弱路径获取原始对象?例如,weakref.proxy()是否与
相反

一个简化示例(python2.7):

我需要从
我的列表
中获取唯一
其他
成员的列表。我喜欢这样的工作方式 要使用
设置

unique_others = {x.other for x in my_list}
不幸的是,这会抛出
TypeError:unhabable类型:“weakproxy”

我已设法以一种紧迫的方式(缓慢而肮脏)解决了具体问题:

但标题中指出的一般问题仍然存在。 如果我只控制了
我的列表
,而
其他的
则埋在一些库中,有人可以随时删除它们,我想通过收集列表中的非弱引用来防止删除,那该怎么办

或者我可能想要获取对象本身的
repr()
,而不是


我想应该有类似于
weakref.unproxy
的东西我不知道。

weakref.ref是可散列的,而weakref.proxy不是。API没有说明如何实际获取代理指向的对象的句柄。有了weakref,这很容易,你可以直接打电话给它。因此,您可以滚动自己的代理类…下面是一个非常基本的尝试:

import weakref
class C(object):
   def __init__(self,obj):
      self.object=weakref.ref(obj)
   def __getattr__(self,key):
      if(key == "object"): return object.__getattr__(self,"object")
      elif(key == "__init__"): return object.__getattr__(self,"__init__")
      else:
          obj=object.__getattr__(self,"object")() #Dereference the weakref
          return getattr(obj,key)

class Other(object):
   pass

others = [Other() for i in range(3)]

my_list = [C(others[i % len(others)]) for i in range(10)]

unique_list = {x.object for x in my_list}

当然,现在unique_列表包含
ref
s,而不是
proxy
s,这是根本不同的…

基本上有类似
weakref.unproxy
,但它只是命名为
weakref.ref(x)(
)。 代理对象仅用于委托,并且实现相当不稳定

==
函数的工作方式与您预期的不同:

>>> weakref.proxy(object) == object
False
>>> weakref.proxy(object) == weakref.proxy(object)
True
>>> weakref.proxy(object).__eq__(object)
True
但是,我发现您不想一直调用
weakref.ref
对象。一个好的具有取消引用支持的工作代理会很好

但目前,这是不可能的。如果查看python内置源代码,您会发现,您需要类似的东西,但根本没有对该方法的调用(并且:如果参数错误,它会引发
PyErr\u BadInternalCall
,因此它似乎是一个内部函数)。使用得更多,但没有一种方法可以做到这一点

所以,很抱歉让您失望,但是您
weakref.proxy
并不是大多数人想要的用例。但是,您可以创建自己的
代理
实现。这并不难。只需在内部使用weakref.ref
,并覆盖
\uuu getattr\uuuu
\uu repr\uuu

关于PyCharm如何生成正常的
repr
输出的一点旁注(因为您在评论中提到了这一点):

>A类():通过
>>>a=a()
>>>weakref.代理(a)
>>>weakref.proxy(a)。_urepr_______;
''
>>>类型(weakref.proxy(a))

正如您所看到的,调用原始的
\uuuu repr\uuu
确实有帮助

我知道这是一个老问题,但我最近在寻找答案,并想出了一些办法。正如其他人所说,没有文档化的方法可以做到这一点,查看weakproxy类型的实现可以确认,没有标准的方法可以实现这一点

我的解决方案使用了这样一个事实:所有Python对象都有一组标准方法(如\uuuu repr\uuu),绑定的方法对象包含对实例的引用(在\uu self\uu属性中)

因此,通过取消对代理的引用以获取方法对象,我们可以从方法对象获得对代理对象的强引用

例如:

>>> def func():
...    pass
...
>>> weakfunc = weakref.proxy(func)
>>> f = weakfunc.__repr__.__self__
>>> f is func
True
另一件好事是,它也适用于强引用:

>>> func.__repr__.__self__ is func
True
因此,如果需要代理或强引用,则不需要进行类型检查

编辑:


我只是注意到这不适用于类的代理。这不是一个普遍的问题。

我知道这是一个老问题,但我已经被它咬了一口(因此,标准库中没有真正的“不稳定”),我想分享我的解决方案

我解决它以获得真实实例的方法只是创建一个返回它的属性(尽管我建议使用
weakref.ref
而不是
weakref.proxy
,因为代码应该在访问它之前真正检查它是否仍然处于活动状态,而不是在访问任何属性时都必须记住捕获异常)

无论如何,如果您仍然必须使用代理,那么获取真实实例的代码是:

import weakref

class MyClass(object):

    @property
    def real_self(self):
        return self

instance = MyClass()
proxied = weakref.proxy(instance)
assert proxied.real_self is instance

API没有,但是像PyCharm这样的IDE能够以某种方式在监视列表窗口中显示repr()的结果。@robyschek当然有可能。我相信您可以在标准库的某个地方找到代码,并找出代理对象是如何工作的……但是如果API中没有对其进行记录,您就不能保证它可以移植到其他python实现中。。。
>>> def func():
...    pass
...
>>> weakfunc = weakref.proxy(func)
>>> f = weakfunc.__repr__.__self__
>>> f is func
True
>>> func.__repr__.__self__ is func
True
import weakref

class MyClass(object):

    @property
    def real_self(self):
        return self

instance = MyClass()
proxied = weakref.proxy(instance)
assert proxied.real_self is instance