Python:Make类iterab

2024-04-26 18:01:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我继承了一个项目,其中有许多大型类,它们只包含类对象(整数、字符串等)。我希望能够检查属性是否存在,而无需手动定义属性列表。

是否可以使用标准语法使python自身可访问?也就是说,我希望能够使用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

Tags: 项目对象字符串inforif属性定义
3条回答

您可以使用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

__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

对于Python3.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

这就是我们如何使类对象可迭代的。为类提供一个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'

这个类迭代类书的属性值。 类对象也可以通过为其提供getitem方法使其成为iterable。 e、 克:

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

现在,当在for in循环中使用BenTen类的对象时,将使用更高的索引值调用getitem,直到它引发indexer错误。

相关问题 更多 >