web-dev-qa-db-ja.com

カスタムオブジェクトを反復可能にする方法は?

カスタムクラスオブジェクトのlistがあります(サンプルは以下です)。

使用:list(itertools.chain.from_iterable(myBigList))すべてのstationsサブリストを1つの大きなリストに「マージ」したいと思いました。そのため、カスタムクラスを反復可能にする必要があると思いました。

これが私のカスタムクラスのサンプルです。

class direction(object) :
    def __init__(self, id) :
        self.id = id              
        self.__stations = list()

    def __iter__(self):
        self.__i = 0                #  iterable current item 
        return iter(self.__stations)

    def __next__(self):
        if self.__i<len(self.__stations)-1:
            self.__i += 1         
            return self.__stations[self.__i]
        else:
            raise StopIteration

__iter____next__を実装しましたが、動作しないようです。彼らも呼ばれていません。

私は何が間違っていたのでしょうか?

注:Python 3.3を使用する

16

__iter__は、クラスインスタンスを反復しようとしたときに呼び出されるものです。

>>> class Foo(object):
...     def __iter__(self):
...         return (x for x in range(4))
... 
>>> list(Foo())
[0, 1, 2, 3]

__next__は、__iter__から返されるオブジェクトで呼び出されるものです(python2.xではnextであり、__next__ではありません-通常は両方にエイリアスを設定して、コードはどちらでも動作します...):

class Bar(object):
   def __init__(self):
       self.idx = 0
       self.data = range(4)
   def __iter__(self):
       return self
   def __next__(self):
       self.idx += 1
       try:
           return self.data[self.idx-1]
       except IndexError:
           self.idx = 0
           raise StopIteration  # Done iterating.
   next = __next__  # python2.x compatibility.
22
mgilson

単に実装する__iter__で十分です。

class direction(object) :
    def __init__(self, id) :
        self.id = id              
        self.__stations = list()

    def __iter__(self):
        #return iter(self.__stations[1:]) #uncomment this if you wanted to skip the first element.
        return iter(self.__stations)


a = direction(1)
a._direction__stations= range(5)

b = direction(1)
b._direction__stations = range(10)

import itertools
print list(itertools.chain.from_iterable([a,b]))
print list(itertools.chain.from_iterable([range(5),range(10)]))

出力:

[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

なぜか here を参照してください_direction__stations

__spam形式の識別子(少なくとも2つの先行アンダースコア、最大で1つの後続アンダースコア)は、テキストでclassname_ spamに置き換えられます。ここで、classnameは現在のクラスです先頭のアンダースコアが削除された名前。

5
M4rtini

listもサブクラス化できます:

class Direction(list):
    def __init__(self, seq=[], id_=None):
        list.__init__(self,seq)
        self.id = id_ if id_ else id(self)

    def __iter__(self):
        it=list.__iter__(self) 
        next(it)                       # skip the first...
        return it  

d=Direction(range(10))
print(d)       # all the data, no iteration
# [0, 1, 2, 3, 4]

print (', '.join(str(e) for e in d))     # 'for e in d' is an iterator
# 1, 2, 3, 4

つまり、最初をスキップします。

ネストされたリストでも機能します:

>>> d1=Direction([range(5), range(10,15), range(20,25)])
>>> d1
[range(0, 5), range(10, 15), range(20, 25)]
print(list(itertools.chain.from_iterable(d1)))
[10, 11, 12, 13, 14, 20, 21, 22, 23, 24]          
3
dawg