ホームページ  >  記事  >  バックエンド開発  >  Python3のrangeはイテレータを返しますか?

Python3のrangeはイテレータを返しますか?

爱喝马黛茶的安东尼
爱喝马黛茶的安东尼転載
2019-06-03 15:31:132886ブラウズ

Pyhton3 の範囲は何を返しますか? Python 2 では range() はリストを返しますが、Python 3 では range が xrange に置き換えられ、反復子 (Iterator) が返されます。

おめでとうございます。答えは間違っていました。

Python3のrangeはイテレータを返しますか?

range() は Iterator ではなく Iterable を返します。

a  Python 3.6.3 (default, Nov  3 2017, 14:41:25)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: a = range(10) 
In [2]: a
Out[2]: range(0, 10)
In [3]: import collections
In [4]: isinstance(a, collections.Iterable)
Out[4]: True 
In [5]: isinstance(a, collections.Iterator)
Out[5]: False

原理は非常に単純です。簡単に説明します。まず、Iterable と Iterator ですが、これら 2 つは根本的に異なる概念であるため、この 2 つを比較しようとしないでください。両方の文字通りの意味は非常に明確です: Iterable は反復可能なオブジェクトであり、それに対して iter(Iterable) を呼び出すと反復子が取得されますが、Iterator は反復子であり、それに対して next(Iterator) を呼び出すと次の要素が取得されます。

Python はプロトコルを支持していますが、率直に言ってこれはアヒル型です。 __iter__() を実装する場合 (つまり、iter() を呼び出すことで Iterator を取得できる場合) は Iterable であり、__next__() と __iter__() を実装する場合は Iterator です。

ちょっと待って、Iterator は次の要素を取得するために next() を呼び出すだけではないでしょうか?なぜ Iterator も Iterable の __iter__() メソッドを実装する必要があるのでしょうか? これは純粋ではありません。

なぜ Python の Iterator は __iter__() を実装するのでしょうか (通常の実装は return self です)。公式ドキュメントには明確にそれが記載されています。

Iterators are required to have an __iter__() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted.

簡単に翻訳すると、多くの場所で受け取られるパラメータが Iterable であるため、Iterator には __iter__() の実装も必要であることを意味します。すべての Iterator が Iterable であれば、これらの Iterable の場所は何の障害もなく使用できます。イテレータを使用します。たとえば、for ループを考えてみましょう。for ループに関しては、Python の wiki (かなり古いものです) で次の説明を見つけました:

Basically, any object with an iterable method can be used in a for loop. Even strings, despite not having an iterable method – but we’ll not get on to that here.

つまり、for ループは Iterable Iterator を取得し、これを使用します。反復を実行するイテレータ。 Iterator が __iter__() メソッドを実装している場合、for ループは何の障害もなく Iterator を反復処理できます。 Python のジェネレーターも Iterator であることを想像してください。for ループが Iterator の反復をサポートできない場合、人生は死よりも悪いものになるでしょう。

つまり、Iterator にはこのような「過剰な」要件が存在します。すべての Iterator は Iterable であると考えることができます。元の質問に戻りますが、なぜ range() は Iterator ではなく Iterable を返すのでしょうか?

通常 range() を使用することを考えると、これは範囲を表すコンテナであると考えられます。このコンテナを使用して他のコンテナを問題なく初期化できます。

>>> numbers = range(3)
>>> tuple(numbers)
(0, 1, 2)
>>> tuple(numbers)
(0, 1, 2)

range() がイテレータを返す場合、上記の一見正常なコードは問題を抱えています。

>>> numbers = iter(range(3))
>>> tuple(numbers)
(0, 1, 2)
>>> tuple(numbers)
()

概要

Iterator はステートフルであり、1 回のみトラバースできます。これは「消費型」であり、「2 回消費」することはできません。 Iterable はステートレスです (ここではあまり厳密ではありません。Iterator の Iterable は言うまでもなく) Iterable で iter() が呼び出されるたびに、新しいイテレータが取得されます。

以上がPython3のrangeはイテレータを返しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はkawabangga.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。