我有一个类在类变量中跟踪它的实例,如下所示:
class Foo:
by_id = {}
def __init__(self, id):
self.id = id
self.by_id[id] = self
Run Code Online (Sandbox Code Playgroud)
我希望能够做的是迭代现有的类实例.我可以这样做:
for foo in Foo.by_id.values():
foo.do_something()
Run Code Online (Sandbox Code Playgroud)
但它看起来像这样整洁:
for foo in Foo:
foo.do_something()
Run Code Online (Sandbox Code Playgroud)
这可能吗?我尝试定义一个类方法__iter__,但这没有用.
glg*_*lgl 28
如果要迭代类,则必须定义支持迭代的元类.
x.py:
class it(type):
def __iter__(self):
# Wanna iterate over a class? Then ask that class for iterator.
return self.classiter()
class Foo:
__metaclass__ = it # We need that meta class...
by_id = {} # Store the stuff here...
def __init__(self, id): # new isntance of class
self.id = id # do we need that?
self.by_id[id] = self # register istance
@classmethod
def classiter(cls): # iterate over class by giving all instances which have been instantiated
return iter(cls.by_id.values())
if __name__ == '__main__':
a = Foo(123)
print list(Foo)
del a
print list(Foo)
Run Code Online (Sandbox Code Playgroud)
正如您在最后看到的那样,删除实例不会对对象本身产生任何影响,因为它保留在by_iddict中.weakref当你使用s时,你可以应付
import weakref
Run Code Online (Sandbox Code Playgroud)
然后呢
by_id = weakref.WeakValueDictionary()
Run Code Online (Sandbox Code Playgroud)
.这样,只要有一个"强"引用保留它,这些值就会保留,例如a在这种情况下.之后del a,只有弱引用指向对象,因此它们可以是gc'ed.
由于有关WeakValueDictionary()s 的警告,我建议使用以下内容:
[...]
self.by_id[id] = weakref.ref(self)
[...]
@classmethod
def classiter(cls):
# return all class instances which are still alive according to their weakref pointing to them
return (i for i in (i() for i in cls.by_id.values()) if i is not None)
Run Code Online (Sandbox Code Playgroud)
看起来有点复杂,但确保您获得对象而不是weakref对象.
魔术方法总是在类上查找,因此添加__iter__到类中将不会使其可迭代.但是,类是其元类的实例,因此元类是定义__iter__方法的正确位置.
class FooMeta(type):
def __iter__(self):
return self.by_id.iteritems()
class Foo:
__metaclass__ = FooMeta
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
23483 次 |
| 最近记录: |