Maison > développement back-end > Tutoriel Python > Définition du générateur Python et analyse d'exemples d'utilisation simples

Définition du générateur Python et analyse d'exemples d'utilisation simples

不言
Libérer: 2018-05-02 16:04:57
original
1223 Les gens l'ont consulté

Cet article présente principalement la définition et l'utilisation simple des générateurs Python. Il analyse en détail les concepts, principes, méthodes d'utilisation et précautions de fonctionnement associées sous forme d'exemples. Les amis dans le besoin peuvent s'y référer

.

Les exemples de cet article décrivent la définition et l'utilisation simple des générateurs Python. Partagez-le avec tout le monde pour votre référence, les détails sont les suivants :

1. Qu'est-ce qu'un générateur

En Python, à cause de la mémoire. limitations, la capacité de la liste est définitivement limitée. Par exemple, si nous créons une liste contenant 100 millions d'éléments, Python ouvrira d'abord suffisamment d'espace en mémoire pour stocker la liste contenant 100 millions d'éléments, puis permettra à l'utilisateur d'utiliser la liste. Cela peut entraîner les problèmes suivants : <.>

1. Il n'y a pas assez d'espace mémoire dans la mémoire pour stocker cette liste, ce qui fait que la liste ne peut pas être créée

2. Même si la liste est créée avec succès, il faudra quand même longtemps, ce qui entraîne une efficacité du programme Faible

3. Si l'utilisateur souhaite accéder uniquement aux premiers éléments de la liste, l'espace occupé par la plupart des éléments de la liste suivante sera gaspillé

Afin de résoudre efficacement les problèmes ci-dessus, Python Un nouveau mécanisme de "

tout en bouclant et en calculant " est introduit signifie que lorsque l'utilisateur a besoin d'utiliser. un objet, Python ouvrira de l'espace mémoire et le créera selon les règles prédéfinies. Cet objet est destiné aux utilisateurs, au lieu de créer tous les objets à l'avance et de les fournir ensuite aux utilisateurs pour qu'ils les utilisent comme une liste. Ce mécanisme est appelé générateur en Python.

2. Création du générateur

A. La formule push du générateur

et List push est similaire, sauf que la compréhension du générateur utilise () au lieu de [], et le générateur est finalement renvoyé à la place de la liste

g=((i+2)**2 for i in range(2,30)) #g是一个生成器
print(g) #g为空,里面包含任何元素
Copier après la connexion
Le résultat de l'exécution est :

< L'objet générateur à 0x0000000002263150>

B. le mot-clé de rendement

contient le mot-clé de rendement dans une définition de fonction, alors cette fonction n'est plus une fonction ordinaire, mais un générateur

[Explication] : L'instruction rendement peut mettre en pause une fonction et renvoyer ses résultats intermédiaires. La fonction utilisant cette instruction sauvegardera l'environnement d'exécution et restaurera si nécessaire <. 🎜>

Résultat d'exécution :
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)
Copier après la connexion

[Remarque] : La différence entre fonctions ordinaires et fonctions qui deviennent des générateurs :

Les fonctions ordinaires sont exécutées séquentiellement et renvoient ou la dernière ligne est rencontrée. L'instruction de fonction renvoie. La fonction qui devient un générateur est exécutée à chaque fois que la méthode __next__() est appelée et retourne lorsqu'elle rencontre une instruction rendement. Lorsqu'elle est à nouveau exécutée, l'exécution continue à partir de l'instruction rendement renvoyée la dernière fois

<. 🎜> Résultat d'exécution :

f=fib(6)
print(f)
print(f.__next__())
print(f.__next__())
print(&#39;暂停一下&#39;)
print(f.__next__())
print(f.__next__())
Copier après la connexion

1
1

Pause un instant
2
3


3. Méthode du générateur (Référence : Bole Online)

Méthode 1.close() : fermez manuellement la fonction du générateur, les appels suivants renverront directement l'exception StopIteration

Résultat d'exécution :

def func():
  yield 1
  yield 2
  yield 3
g=func()
g.__next__()
g.close() #手动关闭生成器
g.__next__() #关闭后,yield 2和yield 3语句将不再起作用
Copier après la connexion

Traceback (dernier appel le plus récent) :

Fichier "E:py3DemoHellogeneratorDemo.py", ligne 9, dans g.__next__() #Après la fermeture, les instructions rendement 2 et rendement 3 ne fonctionneront plus

StopIteration


Méthode 2.__next__() : renvoie le suivant heure de l'appel du générateur

[Explication du processus] :
def func():
  n=1
  for i in range(3):
    yield n
    n+=1
c=func()
a1=c.__next__()
a2=c.__next__()
a3=c.__next__()
Copier après la connexion

Pour les générateurs ordinaires, le premier appel de méthode __next__() est tout à fait Lors du démarrage du générateur, l'exécution commencera à partir de la première ligne de la fonction génératrice jusqu'à ce que l'instruction rendement (la quatrième ligne) soit exécutée pour la première fois, puis la fonction génératrice sautera.

Lorsque la deuxième méthode __next__() est appelée, la fonction génératrice sera rentrée et l'exécution commencera à partir de l'instruction suivante (cinquième ligne) de l'instruction rendement jusqu'à ce qu'elle soit réexécutée. -run. L'instruction rendement sort à nouveau de la fonction génératrice après l'exécution.

Les appels à la méthode __next__() suivants sont de la même manière

Méthode 3.send() : accepte une variable transmise par le à l'extérieur, Et le résultat du calcul est renvoyé à la fonction génératrice en fonction du contenu de la variable

[Note] :

(1) send( ) et la méthode __next__ () sont similaires, la différence est que la méthode send() peut transmettre la valeur de l'expression de rendement, tandis que la méthode __next__() ne peut pas transmettre une valeur spécifique et ne peut transmettre None à l'expression de rendement, donc

Cela peut être compris comme générateur.__next__() comme générateur.send(Aucun)

(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;))
Copier après la connexion

运行结果:

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))
Copier après la connexion

运行结果:

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;)
Copier après la connexion

运行结果:

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装饰器原理与用法分析


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal