Weekly backup.

This commit is contained in:
2022-06-04 12:57:39 +02:00
parent e552583393
commit 015b896f65
68 changed files with 3530 additions and 27 deletions

View File

@@ -0,0 +1,98 @@
:PROPERTIES:
:ID: 67410dad-d959-4029-b281-9bf1c9e69ede
:mtime: 20220529131239
:ctime: 20220529123824
:END:
#+title: Generator
* Introduction
Un /generator/ est :
* Une fonction retournant un /iterable/,
* Un /iterable/ est un /object/ implémentant les méthodes ~__iter__~ et ~__next__~ et génère une erreur ~StopIteration~ lorsqu'il n'y a plus de valeur à retourner,
* Utilise le /statement/ ~yield~ au lieu de ~return~.
Le statement ~return~ termine complètement une fonction alors que ~yield~ la suspend (sauvegarde de son contexte afin
de continuer là où elle en était lors de son prochain appel).
Différences entre une /function/ et un /generator/ :
* Présence d'au moins un ~yield~ dans un ~generator~,
* Le /generator/ retourne un /iterator/ (les méthodes ~__iter__~ et ~__next__~ sont implémentées automatiquement),
* Sauvegarde du contexte d'un /generator/,
* L'erreur ~StopIteration~ est générée automatiquement lors qu'un /generator/ termine.
Les /generator/ sont appropriés quand il est nécessaire de produire un flux de données infini.
#+BEGIN_SRC python :results output
def simple_generator():
for num in range(1, 4):
print(num)
yield num
gen = simple_generator()
next(gen)
next(gen)
next(gen)
try:
next(gen)
except StopIteration as __:
print('StopIteration raised')
for num in simple_generator():
pass
#+END_SRC
#+RESULTS:
: 1
: 2
: 3
: StopIteration raised
: 1
: 2
: 3
Un /generator/ peut être créé soit en déclarant une fonction (cf. exemple précédent) ou directement via une /generator
expression/ :
#+BEGIN_SRC python :results output
list_numbers = [10, 18, 13, 23]
list_square = [x**2 for x in list_numbers]
generator = (x**2 for x in list_numbers)
print(list_square)
print(generator)
#+END_SRC
#+RESULTS:
: [100, 324, 169, 529]
: <generator object <genexpr> at 0x7fae7b90bb30>
* Différences avec /list/
La principale différence entre les /list comprehension/ et les /generator expression/ consiste dans le fait que
l'ensemble de la /list/ est créée par la /list compréhension/ alors que seul un /generator/ est produit par la
/generator expression/. Cela apporte quelques avantages :
* Chaque résultat du /generator/ n'est produit que suite à l'appel de ~__next__~ (/lazy execution/),
* L'espace mémoire nécessaire s'en retrouve réduit,
Il peut s'avérer plus efficace d'utiliser un /generator/ lorsque l'ensemble des résultats ne sera pas utilisé à
l'inverse pour les /list comprehension/.
* Enchainement de /generator/
Il est possible d'enchainer plusieurs /generator/ :
#+BEGIN_SRC python :results output
def fibonacci_numbers(numbers):
x, y = 0, 1
for _ in range(numbers):
x, y = y, x + y
yield x
def square(numbers):
for num in numbers:
yield num**2
print(f'{sum(square(fibonacci_numbers(30))) = }')
#+END_SRC
#+RESULTS:
: sum(square(fibonacci_numbers(30))) = 1120149658760
* Références
* [[https://blog.devgenius.io/what-is-generator-in-python-and-how-does-it-work-e6e0588785c3][What Is Generator in Python and How Does It Work ? - Medium]]