繁体   English   中英

我可以遍历 Python 中的 class 吗?

[英]Can I iterate over a class in Python?

我有一个 class 跟踪它在 class 变量中的实例,如下所示:

class Foo:
    by_id = {}

    def __init__(self, id):
        self.id = id
        self.by_id[id] = self

我想做的是遍历 class 的现有实例。 我可以这样做:

for foo in Foo.by_id.values():
    foo.do_something()

但它看起来像这样更整洁:

for foo in Foo:
    foo.do_something()

这可能吗? 我尝试定义一个类方法__iter__ ,但这没有用。

如果要迭代 ,则必须定义支持迭代的元类。

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)

正如您在最后看到的那样,删除实例不会对对象本身产生任何影响,因为它保留在by_id dict中。 当你使用weakref时,你可以应付这种情况

import weakref

然后呢

by_id = weakref.WeakValueDictionary()

这样的价值观只会只要有一个“强”引用保持它,比如保持a在这种情况下。 del a ,只有弱引用指向该对象,因此它们可以被gc'ed。

由于有关WeakValueDictionary()的警告,我建议使用以下内容:

[...]
    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)

看起来有点复杂,但要确保获得对象而不是weakref对象。

魔术方法总是在类上查找,因此在类中添加__iter__将不会使其可迭代。 但是,类是其元类的实例,因此元类是定义__iter__方法的正确位置。

class FooMeta(type):
    def __iter__(self):
        return self.by_id.iteritems()

class Foo:
    __metaclass__ = FooMeta
    ...

尝试这个:

您可以创建具有全局范围的列表,在主模块中定义列表,如下所示:

fooList = []

然后加:

class Foo:
  def __init__(self):
    fooList.append(self)

到foo类的init

然后,每次创建Foo类的实例时,它都将被添加到fooList列表中。

现在你所要做的就是迭代这样的对象数组

for f in fooList:
    f.doSomething()

您可以创建一个类列表,然后在init方法中调用append,如下所示:

class Planet:
  planets_list = []

  def __init__(self, name):
     self.name = name
     self.planets_list.append(self)

用法:

p1 = Planet("earth")
p2 = Planet("uranus")

for i in Planet.planets_list:
    print(i.name)

您可以创建一个理解列表,然后调用成员方法,如下所示:

  class PeopleManager:         
        def __init__(self):       
           self.People = []        
        def Add(self, person):     
           self.People.append(person) 

  class Person:                
        def __init__(self,name,age): 
           self.Name = name          
           self.Age = age   

  m = PeopleManager()
  [[t.Name,t.Age] for t in m.People]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM