13

有没有办法从指向它的弱代理中获取原始对象?例如,有相反的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_list控制并且others被埋在某个库中并且有人可能随时删除它们,我想通过在列表中收集非弱引用来防止删除怎么办?

或者我可能想获取repr()对象本身的,而不是<weakproxy at xx to Other at xx>

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

4

4 回答 4

8

基本上有类似的东西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如果参数错误,它会引发 a ,所以它似乎是一个内部函数) . 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__代码真的很有帮助!

于 2012-08-12T09:26:00.030 回答
8

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

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

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

例子:

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

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

>>> func.__repr__.__self__ is func
True

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

编辑:

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

于 2015-03-22T22:34:12.727 回答
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 包含refs,而不是proxy根本不同的 s...

于 2012-04-20T13:29:36.500 回答
2

我知道这是一个老问题,但我一直被它所困扰(因此,标准库中没有真正的“非代理”)并想分享我的解决方案......

我解决它以获取真实实例的方法只是创建一个返回它的属性(尽管我建议使用weakref.ref而不是weakref.proxyas 代码应该在访问它之前真正检查它是否仍然存在,而不必记住在任何属性时捕获异常被访问)。

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

import weakref

class MyClass(object):

    @property
    def real_self(self):
        return self

instance = MyClass()
proxied = weakref.proxy(instance)
assert proxied.real_self is instance
于 2018-03-16T11:43:47.073 回答