2020-02-22 23:59:08 +00:00
|
|
|
|
# Python
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
En initiation, on utilise (le for par exemple),
|
|
|
|
|
en avancé on crée (des itérables par exemple).
|
|
|
|
|
|
|
|
|
|
- Exemples concrets et définitions abstraites
|
|
|
|
|
- Pas de `class Foo`, le cerveau ne peut s'accrocher à rien.
|
|
|
|
|
- Le bonheur est dans le chemin et dans la finalité
|
|
|
|
|
- Contenu différenciant
|
|
|
|
|
- Pas de `class Foo`, tout le monde le fait déjà.
|
|
|
|
|
- Détaillez toutes les étapes, même les plus petites.
|
|
|
|
|
- Soyez drôle ! Donnez envie !
|
|
|
|
|
|
|
|
|
|
J'ai 5 jours, donc ~200 slides.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## « Tout est objet »
|
|
|
|
|
|
|
|
|
|
Comme en Java, #oupas
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
- Sortir un interpréteur.
|
|
|
|
|
- Leur faire essayer de deviner ce qui pourrait ne pas être une classe.
|
|
|
|
|
- Démo avec:
|
|
|
|
|
- un nombre entier, #obvious, c'est géré par Python
|
|
|
|
|
- ouvrir une parenthèse si nécessaire, avec 6 ** 6 ** 6
|
|
|
|
|
- un float, en les faisant hésiter vu qu'ils sont « gérés par le CPU »
|
|
|
|
|
- une fonction
|
|
|
|
|
- une classe (et une instance)
|
|
|
|
|
- range !
|
|
|
|
|
- module !!
|
|
|
|
|
|
|
|
|
|
OK mais pas `for`, `def`, ... ce sont des mots clefs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Donc, tout a des attributs…
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Exercice : avec des `set`, et `dir()`, trouver la liste des attributs
|
|
|
|
|
communs à une fonction, disons `max` et à un int, disons `42`,
|
|
|
|
|
combien y'en-a-il ? Moi 23. Combien `object` en a-il ?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Même un int ?
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
>>> (42).__bool__() is bool(42)
|
|
|
|
|
True
|
|
|
|
|
```
|
|
|
|
|
|
2021-03-29 06:35:30 +00:00
|
|
|
|
Ou `help(42 .to_bytes)`.
|
|
|
|
|
|
2020-02-22 23:59:08 +00:00
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Ouvrir une parenthèse sur la notion de vérité, ce qui est :
|
|
|
|
|
|
|
|
|
|
- Vide
|
|
|
|
|
- Égal à zéro
|
|
|
|
|
- None ou False
|
|
|
|
|
|
|
|
|
|
c'est faux, le reste, c'est vrai.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Les noms
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Faire le schéma à deux colonnes: noms → mémoire.
|
|
|
|
|
|
2022-03-27 22:00:46 +00:00
|
|
|
|
https://dreampuf.github.io/GraphvizOnline/#%23%20a%3A%20list%20%3D%20%5B%5D%20%20%20%20%20%20%23%20a%3A%20int%20%3D%200%0A%23%20b%20%3D%20a%20%20%20%20%20%20%20%23%20b%20%3D%20a%0A%23%20b.append(1)%20%23%20b%20%3D%20b%20%2B%201%0A%23%20print(a)%20%20%20%20%23%20print(a)%0A%23%20%5B1%5D%20%20%20%20%20%20%20%20%20%23%200%0A%0A%23%20a%20%3D%20%5B%5B%5D%2C%20%5B%5D%5D%0A%23%20b%20%3D%20a%0A%23%20b%5B0%5D.append(5)%0A%23%20print(a)%0A%23%20%5B%5B5%5D%2C%20%5B%5D%5D%0A%0A%23%20import%20math%0A%0A%23%20def%20print_tau()%3A%0A%23%20%20%20...%0A%0A%0Adigraph%20G%20%7B%0A%0A%20%20subgraph%20cluster_0%20%7B%0A%20%20%20%20%20label%20%3D%20%22Noms%22%3B%0A%20%20%20%20%20a%3B%0A%20%20%20%20%20b%3B%0A%20%20%20%20%20math%3B%0A%20%20%20%20%20print_tau%3B%0A%20%20%7D%0A%0A%20%20subgraph%20cluster_1%20%7B%0A%20%20%20%20%20label%20%3D%20%22Objets%22%3B%0A%20%20%20%20%20%22%3Cmodule%20math%3E%22%0A%20%20%20%20%20%22%3Cfunction%20print_tau%3E%22%0A%20%20%20%20%20%22int(5)%22%3B%0A%20%20%20%20%20%22list1(%5B%5Bint(5)%5D%2C%20%5B%5D%5D)%22%3B%0A%20%20%20%20%20%22list2(%5Bint(5)%5D)%22%3B%0A%20%20%20%20%20%22list3(%5B%5D)%22%3B%0A%20%20%20%20%20%22list1(%5B%5Bint(5)%5D%2C%20%5B%5D%5D)%22%20-%3E%20%22list2(%5Bint(5)%5D)%22%0A%20%20%20%20%20%22list1(%5B%5Bint(5)%5D%2C%20%5B%5D%5D)%22%20-%3E%20%22list3(%5B%5D)%22%0A%20%20%20%20%22list2(%5Bint(5)%5D)%22%20-%3E%20%22int(5)%22%0A%20%20%7D%0A%20%20%0A%20%20a%20-%3E%20%22list1(%5B%5Bint(5)%5D%2C%20%5B%5D%5D)%22%0A%20%20b%20-%3E%20%22list1(%5B%5Bint(5)%5D%2C%20%5B%5D%5D)%22%0A%20%20math%20-%3E%20%22%3Cmodule%20math%3E%22%0A%20%20print_tau%20-%3E%20%22%3Cfunction%20print_tau%3E%22%0A%7D
|
2021-03-29 06:35:30 +00:00
|
|
|
|
|
2020-02-22 23:59:08 +00:00
|
|
|
|
En Python avancé bien insister sur le fait qu'un objet en mémoire à
|
|
|
|
|
une adresse.
|
|
|
|
|
|
|
|
|
|
Insister sur le fait qu'un paramètre de fonction n'est qu'un nom. On a
|
|
|
|
|
donc pas de « passage par valeur » chez nous.
|
|
|
|
|
|
|
|
|
|
Bien préciser qu'on ne peut pas « délier » un nom pour le faire
|
2021-03-29 06:35:30 +00:00
|
|
|
|
pointer sur rien (en ce cas on le fait pointer sur `None`).
|
2020-02-22 23:59:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Pendant qu'on parle des noms
|
|
|
|
|
|
|
|
|
|
Leur portée dans une fonction ?
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
In Python, variables that are only referenced inside a function are
|
|
|
|
|
implicitly global. If a variable is assigned a value anywhere within
|
|
|
|
|
the function’s body, it’s assumed to be a local unless explicitly
|
|
|
|
|
declared as global.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## UnboundLocalError
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Faire un exemple dans un fichier.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# J'ai 5mn pour vous parler de `for`
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Déjà, c'est pas un objet.
|
|
|
|
|
|
|
|
|
|
Jusqu'où peut-on creuser ?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## `for` itère sur des itérables
|
|
|
|
|
|
|
|
|
|
- Itérable : Objet dont on peut obtenir les éléments un à un.
|
|
|
|
|
- Itérateur : Représentation d'un flux d'éléments.
|
|
|
|
|
- Séquence : Un itérable dont les éléments sont accessible par indice et dont on connaît la taille.
|
|
|
|
|
- Collection : Itérable dont on connaît la longueur.
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
On peut très bien imaginer un itérateur capable d'itérer un itérable,
|
|
|
|
|
mais aussi une séquence, une collections, ...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Le protocole « séquence »
|
|
|
|
|
|
|
|
|
|
Implémente `__getitem__` et `__len__`.
|
|
|
|
|
|
|
|
|
|
(voir meme `__reversed__`, `__iter__` et `__contains__`).
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Exercice, implémenter un `range()`, mais sans `stop` ni `step`.
|
|
|
|
|
|
|
|
|
|
Petite parenthèse : `range`, c'est une classe ou une fonction ?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Le protocole « séquence »
|
|
|
|
|
|
|
|
|
|
`__getitem__` suffit pour être itérable.
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
C'est l'application du duck-typing : Si ça a tout ce dont `for` à
|
|
|
|
|
besoin, alors ça fonctionne. `for` n'a pas besoin de connaître la
|
|
|
|
|
taille, donc ça fonctionne.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Le protocole d'itération
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Itérable : Objet capable de renvoyer ses éléments un à un.
|
|
|
|
|
Itérateur : Objet chargé de s'occuper de l'itération d'un itérable :
|
|
|
|
|
se souvenir où on en est.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Le protocole d'itération
|
|
|
|
|
|
|
|
|
|
- `iter()` : Crée un itérateur à partir d'un itérable.
|
|
|
|
|
- `next()` : Demande l'élément suivant à un itérateur.
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Première démo REPL sur une liste « on reste utilisateurs de Python ».
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Le protocole d'itération
|
|
|
|
|
|
|
|
|
|
`__iter__` et `__next__`
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Démo REPL sur une liste « on perçoit comment on va pouvoir
|
|
|
|
|
l'implémenter ».
|
|
|
|
|
|
|
|
|
|
La différence ? Petite parenthèse : `iter()` peut utiliser soit le
|
|
|
|
|
protocole séquence soit le protocole d'itération, et fait quelques
|
|
|
|
|
vérifications (que l'itérateur renvoyé soit bien un itérateur).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Petite parenthèse
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
>>> class Counter:
|
|
|
|
|
... def __getitem__(self, i):
|
|
|
|
|
... return i
|
|
|
|
|
...
|
2020-03-01 23:39:47 +00:00
|
|
|
|
>>> i = iter(Counter())
|
2020-02-22 23:59:08 +00:00
|
|
|
|
>>> i
|
|
|
|
|
<iterator object at ...>
|
|
|
|
|
>>> next(i)
|
|
|
|
|
0
|
|
|
|
|
>>> next(i)
|
|
|
|
|
1
|
|
|
|
|
>>> next(i)
|
|
|
|
|
2
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Via le protocole séquence, `__len__` n'est pas utilisé donc ça se
|
|
|
|
|
passe bien.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Petite parenthèse
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
>>> class B: ...
|
|
|
|
|
...
|
|
|
|
|
>>> iter(B())
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
File "<stdin>", line 1, in <module>
|
|
|
|
|
TypeError: 'B' object is not iterable
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
`iter()` donne une belle exception.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Petite parenthèse
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
>>> class C:
|
|
|
|
|
... def __iter__(self): return None
|
|
|
|
|
...
|
|
|
|
|
>>> iter(C())
|
|
|
|
|
Traceback (most recent call last):
|
|
|
|
|
File "<stdin>", line 1, in <module>
|
|
|
|
|
TypeError: iter() returned non-iterator of type 'NoneType'
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
`iter()` valide que `__iter__` renvoie bien un itérateur.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Digression
|
|
|
|
|
|
|
|
|
|
`iter` a aussi une version qui prend deux paramètres.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
from functools import partial
|
|
|
|
|
|
|
|
|
|
with open('mydata.db', 'rb') as f:
|
|
|
|
|
for block in iter(partial(f.read, 64), b''):
|
|
|
|
|
process_block(block)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Retour sur `__iter__`
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def __iter__(self):
|
|
|
|
|
return self
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Mauvaise idée !
|
|
|
|
|
|
|
|
|
|
Réimplémentez la classe `Counter()` comme ça.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Solution
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
class Counter:
|
|
|
|
|
def __init__(self): self.i = -1
|
|
|
|
|
def __iter__(self): return self
|
|
|
|
|
def __next__(self):
|
|
|
|
|
self.i += 1
|
|
|
|
|
return self.i
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Le problème
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
>>> c = Counter()
|
|
|
|
|
>>> for i, j in zip(c, c):
|
|
|
|
|
... print(i, j)
|
|
|
|
|
... if i > 5: break
|
|
|
|
|
...
|
|
|
|
|
0 1
|
|
|
|
|
2 3
|
|
|
|
|
4 5
|
|
|
|
|
6 7
|
|
|
|
|
```
|
|
|
|
|
|
2020-03-01 23:39:47 +00:00
|
|
|
|
|
2020-02-22 23:59:08 +00:00
|
|
|
|
## On recommence
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Cette fois avec un itérateur dédié.
|
|
|
|
|
|
|
|
|
|
|
2020-03-01 23:39:47 +00:00
|
|
|
|
## Solution
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
class BetterCounter:
|
|
|
|
|
def __iter__(self):
|
|
|
|
|
return CounterIterator()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2020-02-22 23:59:08 +00:00
|
|
|
|
## Solution
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
class CounterIterator:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.i = -1
|
|
|
|
|
|
|
|
|
|
def __next__(self):
|
|
|
|
|
self.i += 1
|
|
|
|
|
return self.i
|
2020-03-01 23:39:47 +00:00
|
|
|
|
```
|
2020-02-22 23:59:08 +00:00
|
|
|
|
|
|
|
|
|
|
2020-03-01 23:39:47 +00:00
|
|
|
|
## Solution
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
>>> c = BetterCounter()
|
|
|
|
|
>>> for i, j in zip(c, c):
|
|
|
|
|
... if i > 5: break
|
|
|
|
|
... print(i, j)
|
|
|
|
|
0 0
|
|
|
|
|
1 1
|
|
|
|
|
2 2
|
|
|
|
|
3 3
|
|
|
|
|
4 4
|
|
|
|
|
5 5
|
2020-02-22 23:59:08 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
C'est toujours faux ! Un itérateur doit AUSSI implémenter `__iter__`,
|
|
|
|
|
donc qui `return self`, ça permet d'utiliser aussi les itérateurs avec
|
|
|
|
|
for.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Peut-on faire plus simple ?
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Oui ! Avec un générateur ! C'est le sucre syntaxique pour créer ses
|
|
|
|
|
itérables.
|
|
|
|
|
|
|
|
|
|
Attention, une fonction générateur renvoie un itérateur, (qu'on
|
|
|
|
|
appelle un générateur), pas un itérable ! Et là on est bien contents
|
2020-03-01 23:39:47 +00:00
|
|
|
|
qu'un itérateur ai un `__iter__` qui se renvoie lui même, pour pouvoir
|
2020-02-22 23:59:08 +00:00
|
|
|
|
l'utiliser dans un for !
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Mais alors
|
|
|
|
|
|
|
|
|
|
Si une fonction générateur renvoie un itérateur, et que `__iter__`
|
|
|
|
|
doit renvoyer un itérateur, on peut implémenter `__iter__` avec yield ?
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Oui.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Exemple
|
|
|
|
|
|
|
|
|
|
```python
|
2020-03-01 23:39:47 +00:00
|
|
|
|
class GenCounter:
|
2020-02-22 23:59:08 +00:00
|
|
|
|
def __iter__(self):
|
|
|
|
|
i = 0
|
|
|
|
|
while True:
|
|
|
|
|
yield i
|
|
|
|
|
i += 1
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2020-02-25 20:05:20 +00:00
|
|
|
|
## Pendant qu'on parle de `yield`
|
|
|
|
|
|
|
|
|
|
Connaissez-vous `yield from` ?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Pendant qu'on parle de `for`
|
|
|
|
|
|
|
|
|
|
Connaissez-vous le `else` du `for` ?
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Il ne s'exécute que si le `for` sort sans `break`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## `else`
|
|
|
|
|
|
|
|
|
|
```python
|
2020-03-01 23:39:47 +00:00
|
|
|
|
>>> n = 13
|
|
|
|
|
>>> for i in range(2, n - 1):
|
|
|
|
|
... if n % i == 0:
|
|
|
|
|
... print(f"{n} is not prime")
|
|
|
|
|
... break
|
|
|
|
|
... else:
|
|
|
|
|
... print(f"{n} is prime")
|
|
|
|
|
13 is prime
|
2020-02-25 20:05:20 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Typiquement utile lors des recherches, la sémantique :
|
|
|
|
|
- Trouvé, plus besoin de chercher, break.
|
|
|
|
|
- else: pas trouvé.
|
|
|
|
|
|
|
|
|
|
Fonctionne aussi sur le while.
|
|
|
|
|
|
|
|
|
|
Ah j'ai utilisé une f-string.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Literal String Interpolation
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
>>> f"{42:08b}"
|
2020-03-01 23:39:47 +00:00
|
|
|
|
'00101010'
|
2020-02-25 20:05:20 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Attention aux ':' et '!' dans l'expression, bien que ce soit accepté
|
|
|
|
|
si c'est entre guillemet, crochets, parenthèses, ... sinon toute
|
|
|
|
|
expression Python est autorisée (comme avec .format, mais avec .format
|
|
|
|
|
c'est plus évident).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Literal String Interpolation
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
>>> f"{(lambda x: x.upper())('hello'):^11}"
|
|
|
|
|
' HELLO '
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Attention à rester lisible, mais ici le `:` de la lambda est entre
|
|
|
|
|
parenthèses, donc c'est bon.
|
|
|
|
|
|
|
|
|
|
En parlant de parenthèse, fermons une parenthèse.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## On parlais d'itérables
|
|
|
|
|
|
|
|
|
|
Si on parlais d'unpacking ?
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
Pour se remémorer ces choses, cherchez les PEPs, typiquement la 448, la 3132, ...
|
|
|
|
|
|
2020-03-01 23:39:47 +00:00
|
|
|
|
- Parler de `deep unpacking`.
|
|
|
|
|
- Parler de `head, *rest`, ...
|
|
|
|
|
|
2020-02-25 20:05:20 +00:00
|
|
|
|
|
2020-03-01 23:39:47 +00:00
|
|
|
|
## Ça peut rappeler `*args` et `**kwargs`
|
|
|
|
|
|
|
|
|
|
Notes:
|
2020-02-25 20:05:20 +00:00
|
|
|
|
|
2020-03-01 23:39:47 +00:00
|
|
|
|
Démo si nécessaire.
|