2011-03-25 92 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

相關問題