Python:解除引用weakproxy

时间:2012-04-20 12:19:09

标签: python weak-references

有没有办法从weakproxy指向它的原始对象?例如,是否与weakref.proxy()相反?

一个简化的例子(python2.7):

import weakref

class C(object):
    def __init__(self, other):
        self.other = weakref.proxy(other)

class Other(object):
    pass

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

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

我需要从other获取唯一my_list成员的列表。我喜欢这种任务的方式 是使用set

unique_others = {x.other for x in my_list}

不幸的是,这会引发TypeError: unhashable type: 'weakproxy'

我已设法以命令式方式解决具体问题(缓慢而肮脏):

unique_others = []
for x in my_list:
    if x.other in unique_others:
        continue
    unique_others.append(x.other)

但标题中提到的一般问题仍然有效。 如果我只控制my_listothers被隐藏在某个库中,有人可能会随时删除它们,我想通过收集非弱引用来阻止删除在列表中?

或者我可能希望得到对象本身的repr(),而不是<weakproxy at xx to Other at xx>

我想应该有weakref.unproxy我不知道的事情。

4 个答案:

答案 0 :(得分:6)

基本上有类似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内置源代码,你需要PyWeakref_GetObject这样的东西,但根本没有调用这个方法(并且如果参数错误,它会引发PyErr_BadInternalCall,所以它似乎是一个内部功能)。 PyWeakref_GET_OBJECT使用的更多,但weakref.py中没有方法可以做到这一点。

所以,很抱歉让你失望,但你weakref.proxy并不是大多数人想要的用例。您可以然后进行自己的proxy实施。这并不难。只需在内部使用weakref.ref并覆盖__getattr____repr__

关于PyCharm如何能够产生正常repr输出的一点注释(因为你在评论中提到过):

>>> class A(): pass
>>> a = A()
>>> weakref.proxy(a)
<weakproxy at 0x7fcf7885d470 to A at 0x1410990>
>>> weakref.proxy(a).__repr__()
'<__main__.A object at 0x1410990>'
>>> type( weakref.proxy(a))
<type 'weakproxy'>

如您所见,调用原始__repr__可以提供帮助!

答案 1 :(得分:6)

我知道这是一个古老的问题,但我最近在找一个答案并提出了一些建议。像其他人说的那样,没有记录的方法可以做到这一点,看看weakproxy类型的实现确认没有标准的方法来实现这一点。

我的解决方案使用以下事实:所有Python对象都有一组标准方法(如 __ repr __ ),并且绑定的方法对象包含对实例的引用(在 __ self __ 中)属性)。

因此,通过解除引用代理来获取方法对象,我们可以从方法对象中获得对代理对象的强引用。

示例:

>>> def func():
...    pass
...
>>> weakfunc = weakref.proxy(func)
>>> f = weakfunc.__repr__.__self__
>>> f is func
True

另一个好处是它也适用于强引用:

>>> func.__repr__.__self__ is func
True

因此,如果可以预期代理或强引用,则无需进行类型检查。

修改

我刚注意到这对于类的代理不起作用。这不是普遍的。

答案 2 :(得分:3)

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_list包含ref s,而不是proxy s,这是根本不同的......

答案 3 :(得分:0)

我知道这是一个老问题,但我已经被它咬了(所以,标准库中没有真正的&#39; unproxy&#39;)并想分享我的溶液...

我解决它以获得真实实例的方式只是创建一个返回它的属性(虽然我建议使用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