因此weakref.proxy,weakref.ref当涉及检查引用是否为实时,或者"解引用"它们,或实际上几乎任何方式实际上,对象根本不像对象一样工作.:P
他们似乎仍然有自己的位置 - 比如维护一个响应事件的对象列表.由于一个不需要DEREF它来调用它们是弱引用(不像对象的方法weakref.ref需要被称为第一对象),一个人获得一定的时间从使用的背proxy过几千次迭代的对象.然而,它们似乎更难以实际识别为"死",并且一旦它们引用的对象消失就会立即清理.例子 -
>>> mylist #note the object at mylist[1] is already dead...
[<weakproxy at 0x10ccfe050 to A at 0x10ccf9f50>, <weakproxy at 0x10ccfe1b0 to NoneType at 0x10cb53538>]
>>> for i in mylist[:]:
... try:
... getattr(i, 'stuff') #the second arg could be any sentinel;
... #I just want to hit a ReferenceError
... except AttributeError:
... pass
... except ReferenceError:
... mylist.remove(i)
...
Traceback (most recent call last):
File "<stdin>", line 7, in <module>
ReferenceError: weakly-referenced object no longer exists
Run Code Online (Sandbox Code Playgroud)
所以它存在于那里,它实际上不能直接引用或像变量一样传递,因为这显然会导致Python"取消引用"它并使用它弱指向的对象.(或者其他的东西.)
到目前为止,我发现的唯一似乎有点可靠的是通过try/except路由它,但感觉有点像一个小跑.
for i, obj in enumerate(mylist):
try:
obj.__hash__
except ReferenceError:
del mylist[i]
Run Code Online (Sandbox Code Playgroud)
它可以工作,但Python往往是"所有事情的一个正确答案"语言,这感觉就像一个非常大的解决方案 - 我可能错了,但如果列表足够大,不会复制列表以这种方式适应问题?
不幸的是,这是所有我能似乎真的觉得作为一个潜在的解决,不涉及类型检查或其他垃圾,但我猜我只是错过了的东西weakref如何处理文档weakref.proxy适当的对象.它'感觉''希望确保weakref.proxy不是特殊情况,所以使用a try/except是一次性的实用程序.
因此,如果我在假设中使用try/except此处是正确的,那么有更好的方法来识别死weakref.proxy对象吗?
编辑:我已经接受了答案,所以谢谢你 - 尝试/除了似乎是唯一可以接受的.
至于为什么我没有使用WeakSets - 允许我发布一个简单的演示,最终导致我使用代理对象.
>>> from weakref import WeakSet, proxy
>>> import cProfile
>>> class A(object):
... def __init__(self):
... self.x = 0
... def foo(self, v=1):
... self.x += v
...
>>> Stick = A()
>>> Dave = A()
>>> Jupiter = A()
>>> ##just a list of objects, no fancy
>>> one_group = [Stick, Dave, Jupiter]
>>> cProfile.run("for i in xrange(0, 2**16): [x.foo(i) for x in one_group]")
196610 function calls in 0.136 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
196608 0.049 0.000 0.049 0.000 <stdin>:4(foo)
1 0.087 0.087 0.136 0.136 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
>>> Stick.x
2147450880
>>> Dave.x
2147450880
>>> Jupiter.x
2147450880
Run Code Online (Sandbox Code Playgroud)
所以我们知道它有效,而且我们知道65k迭代的速度相当快.似乎体面; 让我们来看看WeakSets.
>>> ##now a WeakSet of objects. should be ideal; but...
>>> two_group = WeakSet((Stick, Dave, Jupiter))
>>> cProfile.run("for i in xrange(0, 2**16): [x.foo(i) for x in two_group]")
851970 function calls in 0.545 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
196608 0.055 0.000 0.055 0.000 <stdin>:4(foo)
1 0.158 0.158 0.545 0.545 <string>:1(<module>)
65536 0.026 0.000 0.026 0.000 _weakrefset.py:16(__init__)
65536 0.043 0.000 0.051 0.000 _weakrefset.py:20(__enter__)
65536 0.063 0.000 0.095 0.000 _weakrefset.py:26(__exit__)
65536 0.024 0.000 0.024 0.000 _weakrefset.py:52(_commit_removals)
262144 0.159 0.000 0.331 0.000 _weakrefset.py:58(__iter__)
65536 0.009 0.000 0.009 0.000 {method 'add' of 'set' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
65536 0.008 0.000 0.008 0.000 {method 'remove' of 'set' objects}
Run Code Online (Sandbox Code Playgroud)
过早优化?罗.:)这大约慢4倍.啊呀.
>>> ##now finally, a list of proxy objects
>>> three_group = [proxy(x) for x in one_group]
>>> cProfile.run("for i in xrange(0, 2**16): [x.foo(i) for x in three_group]")
196610 function calls in 0.139 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
196608 0.050 0.000 0.050 0.000 <stdin>:4(foo)
1 0.089 0.089 0.139 0.139 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
Run Code Online (Sandbox Code Playgroud)
基于这些数字,我开始认为,维护必须正确注释为已释放的对象列表的最简单,最快的方法是使用代理对象.我认为战略性地使用try/except"列表清理器"将确保死代理不会导致错误.为了方便起见,我可能还会回到使用weakref.ref对象的方法,但代理对象的使用对于它们看似"直接"访问对象很有趣.
您的弱引用对象会再次引发ReferenceError异常,而不是在循环或访问时,很可能是因为 Python 尝试使用代理上的方法。mylist.remove(i)__eq__
您的第二个方法使用索引,并且不会触发该异常,请在第一个循环中使用它:
remove = set()
for index, proxy in enumerate(mylist):
try:
getattr(proxy, 'stuff')
except AttributeError:
pass
except ReferenceError:
remove.add(index)
mylist = [p for i, p in enumerate(mylist) if i not in remove]
Run Code Online (Sandbox Code Playgroud)
演示:
>>> import weakref
>>> class Foo(object): pass
...
>>> remove = set()
>>> mylist = [weakref.proxy(Foo())] # instant dead proxy
>>> for index, proxy in enumerate(mylist):
... try:
... getattr(proxy, 'stuff')
... except AttributeError:
... pass
... except ReferenceError:
... remove.add(index)
...
>>> remove
set([0])
Run Code Online (Sandbox Code Playgroud)
如果您特别想要一个测试对象是否仍然存在的函数,您可以使用:
def proxy_live(p)
try:
bool(p)
except ReferenceError:
return False
return True
Run Code Online (Sandbox Code Playgroud)
但要考虑到布尔测试本身可能会触发对象的删除,如果代理对象挂钩到属性访问、或__nonzero__方法__len__并触发删除。然后,该函数和线程可能会导致竞争条件,其中上述函数将返回True,并且您仍然需要考虑对象上的操作可能会引发ReferenceError.
如果顺序不重要,我会在这里使用一个weakref.WeakSet()对象;当循环这些时,你会得到活动的对象;已经取消引用并为您修剪了死引用,没有竞争条件的风险。
| 归档时间: |
|
| 查看次数: |
614 次 |
| 最近记录: |