2011-03-25 13 views
30

Sınıf nesneleri (tamsayılar, dizgiler, vb.) Dışında hiçbir şey içermeyen birçok büyük sınıfla bir projeyi miras aldım. Özniteliklerin bir listesini manuel olarak tanımlamak için gerek duymadan bir öznitelik olup olmadığını kontrol edebilmek istiyorum.Python: Standart sözdizimini kullanarak bir sınıfın yinelenebilir hale getirilmesi mümkün mü?

Standart sözdizimini kullanarak bir python sınıfı kendini yineleyebilir mi? Yani, bir sınıfın bir örneğini oluşturmaya gerek olmadan for attr in Foo: (veya hatta if attr in Foo) kullanarak bir sınıfın tüm özniteliklerini yineleyebilmek istiyorum. Bunu __iter__ tanımlayarak yapabilirim, ama şu ana kadar aradığım şeyi yönetemedim.

ben şöyle bir __iter__ yöntemi ekleyerek ne istiyorum bazılarını elde ettik:

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

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

Ancak, bu oldukça ben aradığım başarmak gelmez

Buna rağmen, bu işler şu şekilde gerçekleşir:

>>> for x in Foo.__iter__(): 
...  print(x) 
bar 
baz 

cevap

47

yerine sınıfın kendisi (varsayarak Python 2.x) ait metaclass için __iter__ ekleyin: Python 3.x için

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

kullanmak

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

Güzel. OP'nin yaklaşımının neden işe yaramadığını açıklayabilir misiniz? Teşekkürler. – NPE

+6

@aix: OP'nin yaklaşımının işe yaramamasının nedeni, '__iter__' yönteminin yalnızca sınıfın * örnekleri için * çalıştığıdır. Bu, "__iter__' yöntemini metaclassın örneklerine, yani sınıfa kadar dağıtır. – nmichaels

+0

@nmichaels Bu mantıklı, açıklama için teşekkürler. – NPE

7

Sen yineleme yapabilirsiniz for attr in (elem for elem in dir(Foo) if elem[:2] != '__') ile sınıfın gizlenmemiş öznitelikleri üzerinde. o büyü

Daha az korkunç yoludur:

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

sonra

for attr in class_iter(Foo): 
    pass 
+0

cevabını güncelledim Kabul etmeliyim ki OP'den daha pythonic olan bu çözümü tercih ediyorum. Ama onun problemini çözemedim ki ben bulamadım +1 –

5

bu bir sınıf nesnesi iterable yapmak nasıl. sınıfı bir iter ve bir sonraki() yöntemiyle sağlayın, sonra sınıf özniteliklerine veya değerlerine göre yineleyebilirsiniz. İsterseniz, sonraki() yöntemini bırakabilir veya sonraki() öğesini tanımlayıp StopIteration'ı yükseltebilirsiniz. bazı durum.

ör: Sınıf Kitap özellik değeri üzerinde

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' 

bu sınıf dolaşır. Bir sınıf nesnesi, getitem yöntemiyle sağlayarak yinelenebilir hale getirilebilir. örn: o IndexError yükseltir kadar Benten sınıfın nesnesi, bir for-in döngüsünü, GetItem peş peşe yüksek endeks değeri ile çağrılır kullanılır şimdi

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 

.

+0

Bu, bir sınıfın _instance_ öznitelikleri üzerinde yinelemekte (yani 'kitap' kitabında = Kitap (...) '); soru, _class_ özniteliklerini doğrudan (örneğin, 'Kitap' sınıf Kitap (nesne): ') üzerinden yineleme ile ilgilidir. – multipleinterfaces

+0

Bu, OP'nin sorusunun cevabı olmasa da, bu bana yardımcı oldu çünkü yinelenen sınıfı ararken bunu arıyordum. – dlite922