Browse Source

Remove cours/ directory

Now in the book
master
Dimitri Merejkowsky 4 years ago
parent
commit
c8b3df2f4e
6 changed files with 0 additions and 555 deletions
  1. +0
    -1
      cours/.gitignore
  2. +0
    -2
      cours/build.in.ninja
  3. +0
    -21
      cours/build.py
  4. +0
    -378
      cours/classes-01.md
  5. +0
    -9
      cours/deploy.py
  6. +0
    -144
      cours/modules-01.md

+ 0
- 1
cours/.gitignore View File

@@ -1 +0,0 @@
build/

+ 0
- 2
cours/build.in.ninja View File

@@ -1,2 +0,0 @@
rule pandoc
command = pandoc --pdf-engine=xelatex $in -o $out

+ 0
- 21
cours/build.py View File

@@ -1,21 +0,0 @@
from path import Path
import sys
import subprocess


def main():
template = Path("build.in.ninja").text()
to_write = template
for md_file in Path(".").files("*.md"):
to_write += f"build {md_file.with_suffix('.pdf')}: pandoc ../{md_file}\n"
build_path = Path("build")
build_path.mkdir_p()
out = build_path / "build.ninja"
out.write_text(to_write)
process = subprocess.run(["ninja", "-C", build_path])
if process.returncode != 0:
sys.exit(1)


if __name__ == "__main__":
main()

+ 0
- 378
cours/classes-01.md View File

@@ -1,378 +0,0 @@
% Les classes en Python - Partie 1
% Dimitri Merejkowsky


# Rappels sur les fonctions

## Exemple 1

```python
# Définition d'une fonction sans arguments
def ma_fonction():
print("ma_fonction commence ...")
print("bonjour")
print("ma_fonction finit.")

# Appel de la fonction `ma_fonction`:
>>> ma_fonction()
ma_fonction commence ...
bonjour
ma_fonction finit.
```

# Exemple 2

```python
# Définition d'une fonction avec un argument, x:
def ma_fonction(x):
print("x vaut", x)

# Appel de la fonction `ma_fonction`:
>>> ma_fonction(42)
x vaut 42
```

# Aparté - le mot-clé `pass`

En Python, à cause de l'organisation en blocs indentés, on ne
peut pas vraiment avoir de blocs vides. Mais parfois, on
a besoin d'un bloc qui ne fasse rien.

\newpage

Dans ce cas, on peut utiliser le mot-clé `pass`, par exemple
après un if:

```python
une_condition = False
if une_condition:
pass
else:
print("une_condition n'est pas vraie")
```

On peut aussi - et c'est l'usage le plus courant - utiliser `pass` pour
définir une fonction qui ne fait rien:

```python
def ne_fait_rien():
pass
```

```python
>>> ne_fait_rien()
<rien>
```


# Changement de paradigme

Ce qu’on a vu jusqu’ici:

* Des types simples (entiers, booléens, ...)
* Des structures de données (listes, dictionnaires, ...)
* Des fonctions qui manipulent ces types ou ces types
* Des fonctions qui s’appellent les unes les autres

On appelle cet ensemble de concepts, cette façon d'écrire du code, un *paradigme* -
et c'est un paradigme *procédural*.

On va passer à un autre paradigme: l'*orienté objet*.

# Orienté objet - une première définition

Un "objet" informatique *représente* un véritable "objet" physique
dans le vrai monde véritable.

Ce n'est pas une très bonne définition:

1. Ce n'est pas nécessaire
2. Ce n'est même pas forcément souhaitable!

Je le mentionne juste parce que c'est une idée reçue très répandue.

# Orienté objet - 2ème définition

Une meilleure définition, c'est de dire que la programmation
orintée objet permet de mettre au même endroit:

* des données
* des fonctions qui opèrent sur ces données

L'important c'est que les deux aillent ensemble!

*Note: ce n'est pas **la** meilleure définition de l'orienté objet, mais on s'en contentera
pour le moment ...*


# Les classes

On va parler *d'une* façon de faire de l'orienté objet: avec des classes.

Mais notez bien qu'on peut faire de l'orienté objet *sans* classes!

# Le plan de construction

Pour construire un objet en Python, on a besoin d'un *plan de construction*.

On appelle ce plan une *classe* et on la définit ainsi:

```python
class MonObjet:
# du code ici
```

Comme les fonctions, les classes contienent un *corps*, qui est le bloc *identé* en dessous
du mot-clé `class`, de nom de la classe et du `:` en fin de ligne

# Créons des objets

On peut faire un plan de construction vide avec le mot clé pass:

```python
class MonObjet:
pass
```

Dans ce cas, on crée un objet en mettant le nom de la classe suivi d'une paire de parenthèses -
un peu comme pour appeler une fonction:

```python
>>> objet_1 = MonObjet()
```

Ici, `objet_1` est une *instance* de la classe `MonObjet`.

# Attributs

Les attributs sont des éléments **nommés** à *l'intérieur* d'un objet.

On peut y accéder avec la syntaxe `<objet>.<attribut>`:

```python
y = a.x
```

Ici, `y` est l'attribut `x` de l'objet `a`.

Les attributs peuvent être des fonctions:

```python
func = a.x
func(10)
```

Ici, on crée une variable `func` qui prend la valeur de l'attribut `x` dans l'objet `a`, puis
on l'appelle avec l'argument `10` à la ligne suivante.

Le code suivant fait exactement la même chose, mais avec une ligne de moins:

```python
a.x(10)
```

On peut *créer* des attributs dans *n'importe quel objet*, en utilisant l'*assignation*:

```python
>>> mon_instance = MonObjet()

# Création de l'attribut `x` dans `mon_instance`
>>> mon_instance.x = 42

# Accés à l'attribut `x` dans `mon_instance`
>>> mon_instance.mon_attribut
42
```

# Méthodes - définition

On peut aussi mettre des *méthodes* dans des classes.

On utilise `def`, comme pour les fonctions, mais les méthodes *doivent* avoir au
moins un argument appelé `self`, et être à l'intérieur du bloc de la classe:

```python
class MonObjet:
def ma_méthode(self):
return 42
```

# Méthodes - appel

Une méthode ne peut être appelée que depuis une *instance* de
l'objet:

```python
class MonObjet:
def ma_méthode(self):
return 42
>>> ma_méthode()
Erreur

>>> mon_instance = MonObjet()
>>> mon_instance.ma_méthode()
42
```

Notez qu'on ne passe *pas* d'argument quand on apelle `ma_méthode` depuis l'instance de l'objet.


# Méthodes et attributs

`self` *prend la valeur de l'instance courante* quand la méthode est appelée.

On peut le voir en utilisant des attributs:

```python
class MonObjet:
def affiche_attribut_x(self):
# Accès à l'attribut `x` dans `self`
print(self.x)


>>> mon_instance = MonObjet()
>>> mon_instance.x = 42
>>> mon_instance.affiche_attribut_x()
42
```

On peut aussi *créer* des attributs dans une méthode:

```python
class MonObjet:
def crée_attribut_x(self):
self.x = 42
def affiche_attribut_x(self):
print(self.x)

>>> mon_instance = MonObjet()
>>> mon_instance.affiche_attribut_x()
# Erreur: `mon_instance` n'a pas d'attribut `x`

>>> mon_instance.crée_attribut_x()
>>> mon_instance.affiche_attribut_x()
42
```

Les méthodes peuveunt aussi prendre plusieurs arguments, en plus de `self` - mais `self` doit
toujours être le premier argument.

Par example, pour créer un attribut avec une certaine valeur:


```python
class MonObjet
def crée_attribut_x(self, valeur_de_x):
self.x = valeur_de_x

def affiche_attribut_x(self);
print(self.x)

>>> mon_instance = MonObjet()
>>> mon_instance.crée_attribut_x(42)
>>> mon_instance.affiche_attribut_x()
42
```

# Méthodes appelant d'autres méthodes

Comme les méthodes sont *aussi* des attributs, les méthodes d'un objet peuvent s'appeler
les unes les autres:

```python
class MonObjet:
def méthode_1(self):
print("démarrage de la méthode 1")
print("la méthode 1 affiche bonjour")
print("bonjour")
print("fin de la méthode 1")


def méthode_2(self):
print("la méthode 2 appelle la méthode 1")
self.méthode_1()
print("fin de la méthode 2")
```


```python
>>> mon_instance = MonObjet()
>>> mon_instance.méthode_2()
```

```text
la méthode 2 appelle la méthode 1
démarrage de la méthode 1
la méthode 1 affiche bonjour
bonjour
fin de la méthode 1
fin de la méthode 2
```

# Une méthode spéciale

Si vous définissez une méthode `__init__`, celle-ci est appelée *automatiquement*
quand l'objet est construit.

On dit que c'est une méthode "magique" parce qu'elle fait quelque chose _sans_ qu'on
l'appelle explicitement.

On utilise souvent `__init__` pour créer des attributs


```python
class MonObjet:
def __init__(self):
self.x = 1
self.y = 2

>>> mon_instance = MonObjet()

# __init__ est appelée automatiquement!
>>> mon_instance.x
1
>>> mon_instance.y
2
```


On prend souvent les *valeurs* des attributs à créer en arguments de la méthode `__init__ `.

```python
class MonObjet:
def __init__(self, x, y):
self.x = x
self.y = y
```

Dans ce cas, les arguments de la méthode `__init__` apparaissent à l'intérieur des parenthèses après le
nom de la classe:

```
>>> mon_instance = MonObjet(3, 4)
>>> mon_instance.x
3
>>> mon_instance.y
4
```

*Pour cette raison, `__init__` est souvent appelé le _constructeur_ de la classe.*

# Récapitulatif

* Classe: plan de construction
* Objet: ce qu'on crée avec le plan
* Attribut: variable dans un objet
* Instance: objet issue d'une classe
* Méthode: fonction dans une classe (qui prend `self` en premier argument)
* `__init__`: méthode magique appelée automatiquement pendant l'instaciation


# Classes et programmation orienté objet

Ainsi, on peut ranger au même endroit des données et des fonctions opérant sur ces donées.

Les donées sont les attributs, et les fonctions opérant sur ces attributs sont les méthodes.

On peut ainsi séparer les *responsabilités* à l'intérieur d'un code en les répartissant
entres plusieurs classes.

+ 0
- 9
cours/deploy.py View File

@@ -1,9 +0,0 @@
import subprocess


def main():
subprocess.run("rsync --itemize-changes build/*.pdf dedi3:/srv/nginx/e2l/python/", shell=True)


if __name__ == "__main__":
main()

+ 0
- 144
cours/modules-01.md View File

@@ -1,144 +0,0 @@
% Les modules en Python - Partie 1
% Dimitri Merejkowsky

# Un fichier = un module

Et oui, vous faites des modules sans le savoir depuis le début :)

Un fichier `foo.py` correspond *toujours* module `foo`

**Attention: Ce n'est pas tout à fait réciproque. Le module `foo` peut venir d'autre chose
qu'un fichier foo.py.**

# Importer un module

Ou: accéder à du code provenant d'un *autre* fichier source.

Imaginons un fichier `bonjour.py` contenant seulement une assignation
d'une variable `a` à l'entier 42 :

```python
# Dans bonjour.py
a = 42
```

On peut accéder à cette variable en important le module, par
exemple depuis l'interpréteur, en utilisant le mot-clé `import`
suivi du nom du module:

```python
$ python
>>> import bonjour
>>> bonjour.a
42
```

Notez que pour que cela fonctionne:

* Le nom du module est écrit directement, ce n'est *pas* une
chaîne de caractères.
* Il faut lancer la commande `python` sans argument
* Il faut la lancer depuis le répertoire qui contient `bonjour.py`.

On voit que l'assignation de la variable `a` dans `bonjour.py` est devenue
un *attribut* du module `bonjour` lorsque `bonjour` a été importé

\newpage

Si maintenant on rajoute une fonction `dire_bonjour` dans `bonjour.py`:

```python
# toujours dans bonjour.py
a = 42
def dire_bonjour():
print("Bonjour!")
```

On peut appeler la fonction `dire_bonjour` depuis l'interpréteur en accédant
à l'attribut `dire_bonjour` du module `bonjour`:

```python
>>> import bonjour
>>> bonjour.dire_bonjour()
Bonjour!
```

# Différence avec la commande python

Notez bien que lancer l'interpréteur et taper `import bonjour` dedans n'est pas
la même chose que lancer `python bonjour.py`.

Dans le deuxième cas, tout le code dans `bonjour.py` est exécuté, puis la commande python
se termine.

Dans le cas de l'interpréteur, on peut utiliser tous les attributs du module et appeler
les fonctions autant de fois qu'on veut:

```python
>>> import bonjour
>>> bonjour.dire_bonjour()
Bonjour!
>>> bonjour.dire_bonjour()
Bonjour!
```

On peut aussi modifier les valeurs des attributs:

```python
>>> import bonjour
>>> bonjour.a
42
>>> bonjour.a = 36
>>> bonjour.a
36
```



# Les imports ne sont faits qu'une seule fois

Il est important de noter que le code à l'intérieur d'un
module n'est *pas* ré-éxécuté si le module a déjà été
importé auparavant.

On peut le voir en mettant du code dans `bonjour.py`,
en plus des simples définitions de fonctions et assignations
de variables
```python
# Dans bonjour.py
print("Je suis le module bonjour et tu viens de m’importer")
```

```python
>>> import bonjour
Je suis le module foo et tu viens de m’importer
>>> import bonjour
<rien>
```

Il faudra donc redémarrer l'interpréteur à chaque fois que le code dans `bonjour.py` change.

# La bibliothèque standard

La bibliothèque standard est une collection de modules directement utilisables fournis à l'installation de Python.

Exemple: `sys`, `random`, ...

Toute la bibliothèque standard est documentée - et la traduction en Français est en cours:

https://docs.python.org/fr/3/library/index.html

Mettez ce lien dans vos favoris - il vous sera très utile.

# Quelques exemples de modules de la bibliothèque standard

## Easter eggs

(Ou fonctionnalités cachées)

* `import antigravity`
* `import this`

Je vous laisse découvrir ce que fait le premier. Quant au deuxième, il contient
une liste de préceptes que la plupart des développeurs Python s'efforcent de
respecter. On en reparlera ...