Python のイテレータを理解する

黄舟
リリース: 2016-12-16 11:38:48
オリジナル
1057 人が閲覧しました

反復とは

for ループ内で直接使用できるオブジェクトを総称して反復可能オブジェクト (Iterable) と呼びます。
next() 関数で呼び出すことができ、継続的に次の値を返すオブジェクトをイテレータと呼びます。
すべての Iterable は、組み込み関数 iter() を通じて Iterator に変換できます。

イテレータの場合は、1 つの __next__() で十分です。 for ステートメントと in ステートメントを使用すると、プログラムは処理対象のオブジェクトのイテレータ オブジェクトを自動的に呼び出し、StopIteration 例外が検出されるまで __next__() メソッドを使用します。

>>> L = [1,2,3]
>>> [L の x**2]
>>> (L)
トレースバック (最後の呼び出し):
ファイル ""、 の 1 行目
TypeError: 'list' オブジェクトは反復子ではありません
>>> (L)
>>> 次へ (I)
1
>>> 次へ (I)
2
> (I)
トレースバック (最新の呼び出し):
ファイル "
StopIteration


上の例では、リスト L は for でループできますが、組み込み関数では使用できません next() は次の値を見つけるために使用されるため、L反復可能です。
L は iter によってパッケージ化され、I に設定されます。I は次の値を見つけるために next() によって使用できるため、I はイテレーターです。

余談:

組み込み関数 iter() はオブジェクトの __iter__() メソッドのみを呼び出すため、リスト オブジェクト内にメソッド __iter__() が存在する必要があります

組み込み関数 next() は、オブジェクトの _ _next__() メソッドであるため、メソッド __next__() はリスト オブジェクト内に存在してはなりませんが、このメソッドは Itrator 内に存在する必要があります。

実際、for ループ内では、ループの反復前に iter() が最初に呼び出され、Iterable が Iterator に変わります。

>>> L = [4,5,6]

>>> I = L.__iter__()

>>> Traceback (最新の呼び出し) ):

ファイル ""、 の 1 行目
AttributeError: 'list' オブジェクトには属性 '__next__' がありません
>>> I.__next__()
4
> ;> コレクションからインポート Iterator、Iterable
>>> isinstance(L, Iterable)
True
>>>
>>> [x**2 for x in I]
[25, 36]


Iterator は Iterable から継承します。以下のテストから、Iterator に __iter__() と __next__() が含まれていることが簡単にわかります。メソッド、一方 Iteratble には __iter__() のみが含まれます。

>>> コレクションからの Iterator、Iterable
>>> クラス Iterator:
class Iterable) のヘルプ:
| object
|**注: ここから、Iterable は object から継承し、Iterator は Iterable から継承することがわかります。
| ここで定義されるメソッド:

| __iter__(self)

| __next__(self)

| 使い果たされた場合、StopIteration

>>> ; help(Iterable)
クラス Iterable のヘルプ:

class Iterable(builtins.object)
| ここで定義されているメソッド:
|
(self)
......


iterable には __iter__ ( ) メソッドはイテレータを返すために使用され、イテレータにはループされる __next__() メソッドが含まれている必要があります

イテレータを自分で定義する場合は、クラスで __iter__() 関数を定義し、それを使用して __next__( ) メソッドオブジェクトで十分です。
コードに直接移動します

class Iterable:
def __iter__(self):
return Iterator()

class Iterator:
def __init__(self):
self.start=-1
def __next__(self):
self.Start += 2 iF Self.start & GT; 10:
Raise Stop An
Return Self.start

i = Iterable ()

I の場合: Print (i)


上記のコードは、10 以内の奇数を見つけるコードです。コード内のクラス名は、上記で指定したクラス名を使用する必要はありません。
StopIteration 例外が Iterator の __next__ メソッドに実装されていない場合、表されるすべての奇数が実装されている場合、呼び出し時にループを終了するための条件を設定する必要があります。

class Iterable:
def __iter__(self):
return Iterator()

class Iterator:
def __init__(self):
self.start=-1
def __next__(self):
self.start +=2
return self.start

I = Iterable()
for count, i in zip(range(5),I): #組み込み関数 enumerate を使用してカウント作業を実装することもできます。
Print(i)

印刷する要素の数を実現するために range を使用します。ここでは、5 つの要素を印刷することを意味し、返される結果は上記と一致します。

もちろん、これら 2 つのクラスをマージしてプログラムを簡素化することもできます。
最終版は以下の通りです

class Iterable:
def __iter__(self):
def return self
def self.start=-1
def __next__(self):
self.start +=2
if self .start & gt; 10:
Raise Stoption
Return Self.start

i = ITERABLE ()
I の I の場合:
Print (i)

コピー イテレータは 1 回限りのコンシューマーであり、完了しました。これ以降は空になります。ぜひご覧ください。

>L=[1,2,3]

>I=iter(L)

>fori:

... print(i, end='-')
...
1-2-3-
>>>next(I)
トレースバック (最新の呼び出し最後):
ファイル ""、行 1、in
StopIteration


ループが使い果たされると、呼び出しが再度使用されると StopIteration 例外がスローされます。

次回使用できるように、直接代入を通じてイテレータを保存したいと考えています。

しかし、以下の例からわかるように、それはまったく機能しません。

>>> I=iter(L)>>> 次(I)
1

>>>

>>> next(I)
3
>>> next(J)
トレースバック (最後の呼び出し):
ファイル ""、 の行 1
StopIteration


それでは、どうすれば望む効果を達成できるでしょうか?
コピー パッケージで deepcopy を使用する必要があります。以下を参照してください:

>>> I=iter(L)
>>> (I)

>>> 次へ (I)

1
>>> 次へ (I)

2

> 戻ることはできません。
したがって、後退などの機能を実現するには、何か特別な操作を行う必要があります。

上記のコードはすべて Python 3.4 でテストされています。

上記は Python のイテレータを理解するための内容です。その他の関連記事については、PHP 中国語 Web サイト (www.php.cn) をご覧ください。



関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート