Pythonジェネレータの定義と簡単な使用例分析

不言
リリース: 2018-05-02 16:04:57
オリジナル
1215 人が閲覧しました

この記事では、Python ジェネレーターの定義と簡単な使用法を主に紹介し、Python ジェネレーターの概念、原理、使用方法、関連する操作上の注意点をサンプルの形式で詳しく説明します。 Python ジェネレーターの定義と簡単な使用例の例。参考のために皆さんと共有してください。詳細は次のとおりです:

1. ジェネレーターとは Python では、メモリの制限により、リストの容量には確実に制限があります。たとえば、1 億個の要素を含むリストを作成すると、Python はまず 1 億個の要素を含むリストを保存するのに十分なスペースをメモリ内に確保してから、ユーザーがそのリストを使用できるようにします。これにより、次の問題が発生する可能性があります。

1. このリストを保存するのに十分なメモリ領域がメモリ内にないため、リストを作成できません

2. リストの作成に成功した場合でも、依然として時間がかかり、プログラムのパフォーマンスが低下します効率

3. ユーザーのみがリストの最初のいくつかの要素にアクセスしたい場合、後続のリストのほとんどの要素が占めるスペースは無駄になります

上記の問題を効果的に解決するために、Python には「

計算中のループ

」メカニズムの新しいメソッドが導入されました。

つまり、ユーザーがオブジェクトを使用する必要がある場合、Pythonはメモリ空間を開き、事前に設計されたルールに従ってユーザーが使用できるようにこのオブジェクトを作成します、リストのように事前にすべてのオブジェクトを作成してからユーザーに提供するのではなく、を使用します。この仕組みをPythonではジェネレーターと呼びます。

2. ジェネレーターの作成

A. ジェネレーターのプッシュ式

は、ジェネレーターの導出で [] の代わりに () を使用し、最終的な戻り値が以下である点を除き、リスト プッシュ式と似ています。これはリストではなくジェネレーターです

g=((i+2)**2 for i in range(2,30)) #g是一个生成器
print(g) #g为空,里面包含任何元素
ログイン後にコピー

演算結果:

at 0x0000000002263150>

関数定義に yield キーワードが含まれています。この関数はもはや通常の関数ではなく、ジェネレーターです

[説明]: yield 命令は関数を一時停止し、その中間結果を返すことができます。この命令を使用する関数は実行環境を保存し、必要に応じて更新します。

def fib(max):
  n,a,b=0,0,1
  while n<max:
    #print(b)
    yield b
    a,b=b,a+b
    n+=1
  return &#39;done&#39;
f=fib(6)
print(f)
ログイン後にコピー

の操作結果を復元する場合:

[注]: 通常の関数とジェネレーターになる関数の違い:

注文が実行されると、 return または function ステートメントの最後の行に遭遇すると、戻ります。ジェネレーターとなる関数は、__next__() メソッドが呼び出されるたびに実行され、yield ステートメントに遭遇すると戻り、前回返された yield ステートメントから継続します

f=fib(6)
print(f)
print(f.__next__())
print(f.__next__())
print(&#39;暂停一下&#39;)
print(f.__next__())
print(f.__next__())
ログイン後にコピー

動作結果: < ジェネレーター オブジェクト fib at 0x00000000025631A8>1

1

ちょっと待ってください23

3. ジェネレーター メソッド (参照: Bole Online)




1.close() メソッド:手動で閉じるジェネレーター関数、後で呼び出しは StopIteration 例外を直接返します

def func():
  yield 1
  yield 2
  yield 3
g=func()
g.__next__()
g.close() #手动关闭生成器
g.__next__() #关闭后,yield 2和yield 3语句将不再起作用
ログイン後にコピー

操作結果:

トレースバック (最新の呼び出しは最後): ファイル "E:py3DemoHellogeneratorDemo.py"、9 行目、

g .__next__() # 閉じた後、yield 2 および yield 3 ステートメントは機能しなくなります

StopIteration

2.__next__() メソッド: ジェネレーターの次の呼び出しを返します

def func():
  n=1
  for i in range(3):
    yield n
    n+=1
c=func()
a1=c.__next__()
a2=c.__next__()
a3=c.__next__()
ログイン後にコピー


[プロセスの説明]:

通常のジェネレーターの場合、最初の __next__() メソッドの呼び出しはジェネレーターの開始に相当します。このとき、ジェネレーター関数の 1 行目から、yield ステートメント (4 行目) が実行されるまで実行が開始されます。初回は、デバイス機能が終了します。

2 番目の __next__() メソッドが呼び出されると、ジェネレーター関数が再入力され、yield ステートメントが再実行されるまで、yield ステートメントの次のステートメント (5 行目) から実行が開始されます。デバイス関数実行後に世代が再度飛び出します。

次の __next__() メソッド呼び出しは上記と同じです

3.send() メソッド: 外部から渡された変数を受け取り、変数の内容に従って結果を計算し、メソッドに返します。ジェネレーター関数

[注]:

(1) send() メソッドは __next__() メソッドに似ていますが、send() メソッドは yield 式の値に渡せる点が異なります。 __next__() メソッドは特定の値を渡すことはできませんが、yield 式には None だけを渡すことができるため、generator.__next__() はgenerator.send(None) として理解できます

(2)第一次调用生成器函数时,必须使用__next__()语句或是send(None),不能使用send发送一个非None的值给生成器函数,否则会出错,因为没有yield语句来接收这个值

def gen():
  value=0
  while True:
    receive=yield value
    if receive==&#39;end&#39;:
      break
    value=&#39;Got:%s&#39; %receive
g=gen()
print(g.__next__()) #或是print(g.send(None)),从而启动生成器
print(g.send(&#39;aaa&#39;))
print(g.send(3))
print(g.send(&#39;end&#39;))
ログイン後にコピー

运行结果:

0
Got:aaa
Got:3
Traceback (most recent call last):
File "E:\py3Demo\Hello\generatorDemo.py", line 13, in
print(g.send('end'))
StopIteration

[流程解释]:

a.通过g.send(None)或g.__next__()启动生成器函数,并执行到第一个yield语句结束的位置并将函数挂起。此时执行完了yield语句,但是没有给receive赋值,因此yield value会输出value的初始值0

b.g.send('aaa')先将字符串‘aaa'传入到生成器函数中并赋值给receive,然后从yield语句的下一句重新开始执行函数(第五句),计算出value的值后返回到while头部开始新一轮的循环,执行到yield value语句时停止,此时yield value会输出‘Got:aaa',然后挂起

c.g.send(3)重复步骤b,最后输出结果为‘Got:3'

d.g.send('end')会使程序执行break然后跳出循环,从而函数执行完毕,得到StopIteration异常

4.throw()方法:向生成器发送一个异常。

def gen():
  while True:
    try:
      yield &#39;normal value&#39; #返回中间结果,此处的yield和return的功能相似
      yield &#39;normal value2&#39;
      print(&#39;I am here&#39;)
    except ValueError:
      print(&#39;We got ValueError&#39;)
    except Exception:
      print(&#39;Other errors&#39;)
      break
g=gen()
print(g.__next__())
print(g.throw(ValueError))
print(g.__next__())
print(g.throw(TypeError))
ログイン後にコピー

运行结果:

Traceback (most recent call last):
File "E:\py3Demo\Hello\generatorDemo.py", line 17, in
print(g.throw(TypeError))
StopIteration
normal value
We got ValueError
normal value
normal value2
Other errors

[解释]:

a.print(g.__next__())会输出normal value,并停在yield 'normal value2'之前

b.由于执行了g.throw(ValueError),所以回跳过后续的try语句,即yield ‘normal value2'不会执行,然后进入到except语句,打印出‘We got ValueError'。之后再次进入到while语句部分,消耗一个yield,输出normal value

c.print(g.__next__())会执行yield ‘normal value2'语句,并停留在执行完该语句后的位置

d.g.throw(TypeError)会跳出try语句,因此print('I am here')不会被执行,然后打印‘Other errors',并执行break语句跳出while循环,然后到达程序结尾,打印StopIteration异常的信息

四、生成器的运用

import time
def consumer(name):
  print(&#39;%s准备吃包子啦!&#39; %name)
  while True:
    baozi=yield #接收send传的值,并将值赋值给变量baozi
    print(&#39;包子[%s]来了,被[%s]吃了!&#39; %(baozi,name))
def producer(name):
  c1=consumer(&#39;A&#39;) #把函数变成一个生成器
  c2=consumer(&#39;B&#39;)
  c1.__next__()#调用这个方法会走到yield处暂时返回
  c2.__next__()
  print(&#39;开始准备做包子啦!&#39;)
  for i in range(10):
    time.sleep(1)
    print(&#39;做了一个包子,分成两半&#39;)
    c1.send(i)
    c2.send(i)
producer(&#39;Tomwenxing&#39;)
ログイン後にコピー

运行结果:

A准备吃包子啦!
B准备吃包子啦!
开始准备做包子啦!
做了一个包子,分成两半
包子[0]来了,被[A]吃了!
包子[0]来了,被[B]吃了!
做了一个包子,分成两半
包子[1]来了,被[A]吃了!
包子[1]来了,被[B]吃了!
做了一个包子,分成两半
包子[2]来了,被[A]吃了!
包子[2]来了,被[B]吃了!
做了一个包子,分成两半
包子[3]来了,被[A]吃了!
包子[3]来了,被[B]吃了!
做了一个包子,分成两半
包子[4]来了,被[A]吃了!
包子[4]来了,被[B]吃了!
做了一个包子,分成两半
包子[5]来了,被[A]吃了!
包子[5]来了,被[B]吃了!
做了一个包子,分成两半
包子[6]来了,被[A]吃了!
包子[6]来了,被[B]吃了!
做了一个包子,分成两半
包子[7]来了,被[A]吃了!
包子[7]来了,被[B]吃了!
做了一个包子,分成两半
包子[8]来了,被[A]吃了!
包子[8]来了,被[B]吃了!
做了一个包子,分成两半
包子[9]来了,被[A]吃了!
包子[9]来了,被[B]吃了!

相关推荐:

Python迭代器定义与简单用法分析

Python装饰器原理与用法分析


以上がPythonジェネレータの定義と簡単な使用例分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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