Pythonの反復は、紙、イテレータと発電機の概念を知ることができます


プログラム猿思慮深く、生涯学習の専門家は、スタートアップのチームで、現在どのチームリーダーである、技術スタックは、AndroidやPython、Java、および移動を必要とする、これが主な技術が私たちのチームをスタックです。
GitHubの:https://github.com/hylinux1024
マイクロチャネルパブリック番号:生涯現像剤(angrycode)

Python(反復可能Iterable(イテレータ)Iterator)及び発電機(Generator)これらの概念がしばしば使用され、これらのいくつかの初心者はしばしば概念と混同され、把握するいくつかの概念を置くための時間です。

0x00の反復可能な(反復処理可能)

単に長い実現の実現に限り、(Pythonではすべてがオブジェクトである)オブジェクトを置く__iter__()方法、そしてisinstance()チェックが機能であるIterableオブジェクトは、

例えば

class IterObj:
    
    def __iter__(self):
        # 这里简单地返回自身
        # 但实际情况可能不会这么写
        # 而是通过内置的可迭代对象来实现
        # 下文的列子中将会展示
        return self 

上記クラスの定義IterObjおよび実装する__iter__()方法を、これは缶の反復(反復処理可能)オブジェクト

    it = IterObj()
    print(isinstance(it, Iterable))  # true
    print(isinstance(it, Iterator))  # false
    print(isinstance(it, Generator)) # false

このクラスを覚えておいてください、私たちは、このクラス定義の下に表示されます。

共通の反復可能オブジェクト

ではPythonその共通のiterableはそれを持っていますか?

  1. セットまたはシーケンスタイプ(例えばlisttuplesetdictstr
  2. Fileオブジェクト
  3. クラスで定義され__iter__()た方法のオブジェクトと考えることができるIterableオブジェクトが、反復カスタムオブジェクトができるようにfor正しいサイクルを使用し、確保する必要がある__iter__()実装では(すなわち、内蔵によって正確でなければならないiter()の機能オンIteratorオブジェクト。についてIterator以下説明はちょうどことを覚えて、ピットを残すためにここになりますiter()関数は、その後に、反復可能なイテレータオブジェクトに変身する能力であるfor)を使用
  4. 唯一のクラスで実装されていれば達成__getitem__()オブジェクトが可能なiter()反復の対象イテレータ関数にではなく、自分自身で変換します。だから、オブジェクトができた場合forのサイクルで実行されますが、必ずしもではないIterableオブジェクト。

1,2点は、私たちは次のことを確認することができます

    print(isinstance([], Iterable))  # true list 是可迭代的
    print(isinstance({}, Iterable))  # true 字典是可迭代的
    print(isinstance((), Iterable))  # true 元组是可迭代的
    print(isinstance(set(), Iterable))  # true set是可迭代的
    print(isinstance('', Iterable))  # true 字符串是可迭代的
    
    currPath = os.path.dirname(os.path.abspath(__file__))
    with open(currPath+'/model.py') as file:
        print(isinstance(file, Iterable)) # true

私たちは、見てポイント3

    print(hasattr([], "__iter__")) # true
    print(hasattr({}, "__iter__")) # true
    print(hasattr((), "__iter__")) # true
    print(hasattr('', "__iter__")) # true

これらの組み込みセットまたはシーケンスオブジェクトが持っている__iter__、彼らはメソッドと同じ名前を達成しているプロパティを。しかし、この反復可能オブジェクトをしたいfor、それはビルトインでなければならず、使用サイクルにあるiter()関数呼び出しとに変換Iteratorするオブジェクト。
例えば、我々は組み込みのイテレート可能オブジェクトを見て

    print(iter([])) # <list_iterator object at 0x110243f28>
    print(iter({})) # <dict_keyiterator object at 0x110234408>
    print(iter(())) # <tuple_iterator object at 0x110243f28>
    print(iter('')) # <str_iterator object at 0x110243f28>

これらは、それぞれ対応するイテレータ(に変換されIterator)オブジェクト。
今すぐ戻っての定義の先頭を見てIterObjクラス

class IterObj:
    
    def __iter__(self):
        return self 
        
it = IterObj()
print(iter(it))

我々が使用するiter()機能を、今回Jiangzaiコンソールには、以下の情報をプリントアウトします:

Traceback (most recent call last):
  File "/Users/mac/PycharmProjects/iterable_iterator_generator.py", line 71, in <module>
    print(iter(it))
TypeError: iter() returned non-iterator of type 'IterObj'

エラーの種類があることを意味し、発生したiter()関数がイテレータ型に「非反復子」を転送することはできません。

次に、どのように一つは、反復することができます(Iterableイテレータ(に)オブジェクトIterator)オブジェクト?
私たちは、改訂よIterObjクラスの定義を

class IterObj:

    def __init__(self):
        self.a = [3, 5, 7, 11, 13, 17, 19]

    def __iter__(self):
        return iter(self.a)

私たちは、で指定されたコンストラクタを定義aリストは、また、実装__iter__()方法を。

修飾されたクラスは、することができるiter()すなわちであってもよく、機能を呼び出しfor使用サイクル

    it = IterObj()
    print(isinstance(it, Iterable)) # true
    print(isinstance(it, Iterator)) # false
    print(isinstance(it, Generator)) # false
    print(iter(it)) # <list_iterator object at 0x102007278>
    for i in it:
        print(i) # 将打印3、5、7、11、13、17、19元素

したがってイテレータオブジェクトを定義するとき、我々はに細心の注意を払う__iter__()オブジェクト(例えば、上記セットは、配列、または他のファイルを正しく定義することができる反復の数で知られており、一般的には、実装内部処理ロジック反復可能)を達成するために私たちを支援するために

点4記載ことを意味iter()機能を実現することができる__getitem__()方法イテレータオブジェクトに変換し、ターゲットがであってもよくfor、使用サイクルが、場合isinstance()検出方法時間は、それはイテレータオブジェクトではありません。

class IterObj:
    
    def __init__(self):
        self.a = [3, 5, 7, 11, 13, 17, 19]
    
    def __getitem__(self, i):
        return self.a[i]
        
it = IterObj()
print(isinstance(it, Iterable)) # false
print(isinstance(it, Iterator)) # false
print(isinstance(it, Generator)) false
print(hasattr(it, "__iter__")) # false
print(iter(it)) # <iterator object at 0x10b231278>

for i in it:
    print(i) # 将打印出3、5、7、11、13、17、19

この例では、CAN示す図for使用されているオブジェクトが、それは必ずしもイテレート可能オブジェクトではありません。

今、私たちは要約を行います。

  1. 繰り返しオブジェクト達成することにある__iter__()オブジェクトのメソッドを
  2. それはにあることがありfor、それは満たしている必要があり、使用サイクルiter()コール(すなわち、間違っていることはありません。この関数を呼び出し、適切に回すことができるIteratorオブジェクト)
  3. 反復可能で知られている私たちのカスタム反復可能オブジェクトを達成するために支援することができます。
  4. オブジェクトが実装する__getitem__()方法をすることができるiter()関数に変換Iteratorすることができるforループで使用されるが、それはイテレータオブジェクトでない(使用可能でisinstance検出方法())

0x01の反復子(イテレータ)

多くの場所は、上記しているIterator今、私たちはピットを埋めるために持っています、。
私たちは、イテレータのための反復の概念を理解することができた場合には、よりよく理解されます。
オブジェクトが実装__iter__()及び__next__()方法、それはイテレータオブジェクトです。例えば

class IterObj:

    def __init__(self):
        self.a = [3, 5, 7, 11, 13, 17, 19]

        self.n = len(self.a)
        self.i = 0

    def __iter__(self):
        return iter(self.a)

    def __next__(self):
        while self.i < self.n:
            v = self.a[self.i]
            self.i += 1
            return v
        else:
            self.i = 0
            raise StopIteration()

ではIterObj、リスト、コンストラクタの定義a、リストの長さはn、インデックスi

    it = IterObj()
    print(isinstance(it, Iterable)) # true
    print(isinstance(it, Iterator)) # true
    print(isinstance(it, Generator)) # false
    print(hasattr(it, "__iter__")) # true
    print(hasattr(it, "__next__")) # true

当社は、上記見つけることができ
、コレクションやオブジェクトが反復シーケンスではなく、イテレータです

    print(isinstance([], Iterator)) # false
    print(isinstance({}, Iterator)) # false
    print(isinstance((), Iterator)) # false
    print(isinstance(set(), Iterator)) # false
    print(isinstance('', Iterator)) # false

ファイルオブジェクトは、イテレータです

    currPath = os.path.dirname(os.path.abspath(__file__))
    with open(currPath+'/model.py') as file:
        print(isinstance(file, Iterator)) # true

反復子(Iterator)オブジェクトのみができないforサイクルを使用して、組み込み機能もできnext()関数と呼ばれます。例えば

it = IterObj()
next(it) # 3
next(it) # 5

0x02のジェネレータ(発電機)

今度は、ビルダーが何であるかを見てみましょうか?
発電機はまた、両方の反復イテレータです

発電機は、2つの方法が定義されています。

  1. リストビルダ
  2. 使用してyieldファンクションジェネレータの定義を

ケース1を見てください

    g = (x * 2 for x in range(10)) # 0~18的偶数生成器 
    print(isinstance(g, Iterable)) # true
    print(isinstance(g, Iterator)) # true
    print(isinstance(g, Generator)) # true
    print(hasattr(g, "__iter__")) # true
    print(hasattr(g, "__next__")) # true
    print(next(g)) # 0
    print(next(g)) # 2

データを必要なときにのみ計算されますリストビルダは、膨大なリストを生成するために多くのメモリを消費する必要はないかもしれません。
ケース2を見て

def gen():
    for i in range(10):
        yield i 

このyield効果は、に相当しreturn、この関数の次数を返すある[0,10)自然数で製造することができるnext()、またはfor反復するループ。
プログラムは、遭遇するとyield、キーワード、ジェネレータ関数の戻りを、再び実行するまでnext()の機能を、それは、つまり、最後の実行ポイント関数が返すから継続されますyield終了時に、関数の実行、変数などの位置情報を保存し、この上で、再実行時にyield終了場所をダウンし続けます。
Python発電機のこれらの機能を利用コルーチンを実装することができます。コルーチンは、軽量スレッドとして理解することができ、高い並行性シナリオの治療に関して、それをスレッド多くの利点を有します。

ここで実現コルーチンの表情で生産-消費者モデル

def producer(c):
    n = 0
    while n < 5:
        n += 1
        print('producer {}'.format(n))
        r = c.send(n)
        print('consumer return {}'.format(r))


def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('consumer {} '.format(n))
        r = 'ok'


if __name__ == '__main__':
    c = consumer()
    next(c)  # 启动consumer
    producer(c)

このコードは次のような効果を行い、

producer 1
consumer 1 
producer return ok
producer 2
consumer 2 
producer return ok
producer 3
consumer 3 
producer return ok

コルーチンは達成CPU同時実行を達成するために2つの機能の切り替え効果を。

0x04の引用

  1. https://docs.python.org/3.7/

おすすめ

転載: www.cnblogs.com/angrycode/p/11386970.html