Python:取消引用弱代理



有没有办法从指向它的弱代理中获取原始对象? 例如,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)]

我需要从my_list获取唯一other成员列表。我喜欢的此类任务的方式是使用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_list并且others被埋在某个库中,并且有人可以随时删除它们,并且我想通过在列表中收集非弱引用来防止删除怎么办?

或者我可能想获取对象本身的repr(),而不是<weakproxy at xx to Other at xx> 我想应该有类似我不知道weakref.unproxy的东西。
我知道

这是一个老问题,但我最近正在寻找答案并想出了一些东西。就像其他人说的那样,没有记录的方法可以做到这一点,并且查看弱代理类型的实现确认没有标准方法来实现这一目标。

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

因此,通过取消引用代理以获取方法对象

,我们可以从方法对象中获取对代理对象的强引用。

例:

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

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

>>> func.__repr__.__self__ is func
True

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

编辑:

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

基本上有类似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__确实会有所帮助!

weakref.ref 是可哈希的,而 weakref.proxy 不是。 API 没有说明您如何实际获取代理指向的对象句柄。 使用弱参考,这很容易,你可以调用它。 因此,您可以滚动自己的类似代理的类...这是一个非常基本的尝试:

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,这是根本不同的......

我知道

这是一个老问题,但我被它咬了(所以,标准库中没有真正的"非代理"),想分享我的解决方案......

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

相关内容

  • 没有找到相关文章

最新更新