2011-03-25 59 views
30

我已经继承了一个项目,其中包含许多大类,除了类对象(整数,字符串等)之外没有其他任何东西。我希望能够检查一个属性是否存在,而无需手动定义属性列表。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 

回答

47

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

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

对于Python 3.x中,使用

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

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

不错。请你能解释为什么OP的方法不起作用?谢谢。 – NPE 2011-03-25 15:25:21

+6

@aix:OP的方法不起作用的原因是'__iter__'方法仅适用于类的*实例*。这会将'__iter__'方法碰到元类的实例,即类。 – nmichaels 2011-03-25 15:41:56

+0

@nmichaels这很有道理,谢谢你的解释。 – NPE 2011-03-25 15:42:55

7

可以遍历在类的未隐藏属性与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 
+0

我必须承认我更喜欢这种比OP更加pythonic的解决方案。但它没有解决他的问题,我没有+1 – 2011-03-25 15:38:32

5

这是我们如何做一个类的对象迭代。为该类提供一个iter和next()方法,然后您可以迭代类属性或它们的值。如果需要,可以保留next()方法,或者可以定义next()并在其上引发StopIteration一些条件。

e.g:

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方法来进行迭代。 e.g:

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循环,的GetItem调用与succesively较高索引值被使用,直到它提出IndexError。

+0

这反复遍及类的_instance_的属性(即'book = Book(...)'中的'book');问题是关于直接迭代_class_属性(即'Book Book(object):'中的'Book')。 – multipleinterfaces 2013-01-02 15:45:42

+0

虽然这不是OP的问题的答案,但它帮助我,因为我在寻找可迭代类时正在寻找这个。 – dlite922 2013-03-22 18:04:13

相关问题