Python:使类可迭代

问题描述 投票:37回答:5

我继承了一个包含许多大型类的项目,这些大型类仅由类对象(整数,字符串等)组成。我希望能够检查是否存在属性,而无需手动定义属性列表。

是否可以使用标准语法使python class本身可迭代?也就是说,我希望能够使用for attr in Foo:(甚至if attr in Foo)对类的所有属性进行迭代,而无需首先创建类的实例。我想我可以通过定义__iter__来做到这一点,但到目前为止,我还没有完全掌握要寻找的内容。

我通过添加如下的__iter__方法实现了我想要的一些功能:

class Foo:
    bar = "bar"
    baz = 1
    @staticmethod
    def __iter__():
        return iter([attr for attr in dir(Foo) if attr[:2] != "__"])

但是,这并不能完全满足我的要求:

>>> for x in Foo:
...     print(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'classobj' object is not iterable

即使如此,这仍然有效:

>>> for x in Foo.__iter__():
...     print(x)
bar
baz
python syntax attributes static-methods loops
5个回答
55
投票

__iter__添加到元类中,而不是类本身(假设Python 2.x):

class Foo(object):
    bar = "bar"
    baz = 1
    class __metaclass__(type):
        def __iter__(self):
            for attr in dir(self):
                if not attr.startswith("__"):
                    yield attr

对于Python 3.x,使用

class MetaFoo(type):
    def __iter__(self):
        for attr in dir(self):
            if not attr.startswith("__"):
                yield attr

class Foo(metaclass=MetaFoo):
    bar = "bar"
    baz = 1

8
投票

您可以使用for attr in (elem for elem in dir(Foo) if elem[:2] != '__')遍历类的未隐藏属性。

一种不太可怕的拼写方式是:

def class_iter(Class):
    return (elem for elem in dir(Class) if elem[:2] != '__')

然后

for attr in class_iter(Foo):
    pass

7
投票

这就是我们使类对象可迭代的方式。为类提供iter和next()方法,然后可以遍历类属性或其值。如果需要,可以保留next()方法,也可以定义next()并引发在某些情况下StopIteration。

例如:

class Book(object):
      def __init__(self,title,author):
          self.title = title
          self.author = author

      def __iter__(self):
          for each in self.__dict__.keys():
              yield self.__getattribute__(each)

>>> book  = Book('The Mill on the Floss','George Eliot')
>>> for each in book: each
...
'George Eliot'
'The Mill on the Floss'

该类遍历Book类的属性值。也可以通过为类对象提供getitem方法来使其可迭代。例如:

class BenTen(object):
    def __init__(self, bentenlist):
        self.bentenlist = bentenlist

    def __getitem__(self,index):
        if index <5:
            return self.bentenlist[index]
        else:
            raise IndexError('this is high enough')

>>> bt_obj = BenTen([x for x in range(15)])
>>>for each in bt_obj:each
...
0
1
2
3
4

现在将BenTen类的对象用于for-in循环中时,使用较高的索引值调用getitem,直到它引发IndexError。


1
投票

从Python 3.4+开始,使用enum.Enum使类可迭代变得容易一些。

enum.Enum

from enum import Enum class Foo(Enum): bar = "qux" baz = 123 >>> print(*Foo) Foo.bar Foo.baz names = [m.name for m in Foo] >>> print(*names) bar baz values = [m.value for m in Foo] print(*values) >>> qux 123 一样,使用这种基于.__dict__的方法的迭代顺序与定义的顺序相同。


0
投票
Enum
© www.soinside.com 2019 - 2024. All rights reserved.