web-dev-qa-db-ja.com

Python:クラスを反復可能にする

私は、クラスオブジェクト(整数、文字列など)だけで構成される多くの大きなクラスを持つプロジェクトを継承しました。属性のリストを手動で定義する必要なく、属性が存在するかどうかを確認できるようにしたいと思います。

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
37

__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
55
Sven Marnach

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
8
nmichaels

これは、クラスオブジェクトを反復可能にする方法です。クラスに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ループで使用されると、IndexErrorが発生するまで、getitemが連続してより高いインデックス値で呼び出されます。

7
vijay shanker

Python 3.4+以降、クラスを反復可能にすることは 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__と同様に、このEnumベースのアプローチを使用した反復の順序は、定義の順序と同じです。

1
Acumenus
class MetaItetaror(type):
    def __iter__(cls):
        return iter(
            filter(
                lambda k: not k[0].startswith('__'),
                cls.__dict__.iteritems()
            )
        )


class Klass:
    __metaclass__ = MetaItetaror

    iterable_attr_names = {'x', 'y', 'z'}
    x = 5
    y = 6
    z = 7


for v in Klass:
    print v
0
sanit