Browse Source

Réécriture de tous les examples avec print()

Bien plus compréhensible qu'avec `>>>`
master
Dimitri Merejkowsky 4 years ago
parent
commit
a3f9c40fa6
23 changed files with 542 additions and 671 deletions
  1. +3
    -0
      cours/TODO
  2. +15
    -0
      cours/source/02-premiers-pas/04-maths-simples.rst
  3. +72
    -0
      cours/source/04-booléens/index.rst
  4. +0
    -98
      cours/source/04-code-source/index.rst
  5. +46
    -18
      cours/source/05-flot-de-controle/01-flot-de-contrôle.rst
  6. +28
    -13
      cours/source/06-fonctions/01-functions.rst
  7. +3
    -3
      cours/source/06-fonctions/02-portée-des-variables.rst
  8. +8
    -6
      cours/source/06-fonctions/04-par-défaut.rst
  9. +19
    -7
      cours/source/06-fonctions/05-fonctions-natives.rst
  10. +10
    -2
      cours/source/06-fonctions/06-return.rst
  11. +87
    -44
      cours/source/07-listes/index.rst
  12. +31
    -42
      cours/source/08-none-et-pass/01-none.rst
  13. +54
    -92
      cours/source/09-dictionnaires/index.rst
  14. +40
    -34
      cours/source/10-tuples/index.rst
  15. +37
    -35
      cours/source/11-classes-01/index.rst
  16. +34
    -55
      cours/source/12-modules-01/index.rst
  17. +15
    -14
      cours/source/13-classes-02/01-couplage.rst
  18. +0
    -176
      cours/source/13-classes-02/01-rappels.rst
  19. +28
    -22
      cours/source/13-classes-02/02-composition.rst
  20. +2
    -3
      cours/source/13-classes-02/index.rst
  21. +1
    -1
      cours/source/14-bibliothèques-01/02-sys.path.rst
  22. +8
    -5
      cours/source/15-fichiers-et-données-binaires/01-données-binaires.rst
  23. +1
    -1
      cours/source/index.rst

+ 3
- 0
cours/TODO View File

@@ -1,2 +1,5 @@
explication des exercices
insérer exercices pour chaque épisode de la saison 2


Explications sur `globals()` et `locals()`

+ 15
- 0
cours/source/02-premiers-pas/04-maths-simples.rst View File

@@ -74,3 +74,18 @@ et on peut utiliser des parenthèses pour grouper les opérations::

print((1 + 2) * 3)
# affiche: 9

Combiner opération et assignation
----------------------------------

La notation ``+=`` permet de combiner addition et assignation::

x = 3
x = x + 1
print(x)
# affiche :: 4

x = 3
x += 1
print(x)
# affiche :: 4

+ 72
- 0
cours/source/04-booléens/index.rst View File

@@ -0,0 +1,72 @@
Chapitre 4 - Booléens et conditions
===================================

En Python, les variables ``True`` et ``False`` sont toujours définies
et servent à représenter une valeur vraie ou fausse.

(Notez qu'elles commencent par une majuscule)

Assignation
-----------

On peut assigner des variables à True ou False::


la_terre_est_plate = False
python_c_est_genial = True


Comparaisons
------------

Certaines opérations renvoient des booléens:

+------+-----------------------------+
|``=`` | égal |
+------+-----------------------------+
|``!=``| différent |
+------+-----------------------------+
|``>`` | strictement supérieur |
+------+-----------------------------+
|``>=``| supérieur ou égal |
+------+-----------------------------+
|``<`` | strictement inférieur |
+------+-----------------------------+
|``<=``| inférieur |
+------+-----------------------------+

Par example::

a = 2
b = 3
print(a > b)
# affiche: False

print(2 + 2 == 4)
# affiche: True

.. warning::

Ne pas confondre: ``==`` pour la comparaison et ``=`` pour l'assignation


Enfin, on peut écrire des encadrements::

a = 3
print(2 <= a < 4)
# affiche: True


not
---

Enfin, on peut utiliser ``not`` pour inverser une condition::

a = 3
if not a == 4:
print("a est différent de 4")
# affiche: a est différent de 4

la_terre_est_plate = False
print(not la_terre_est_plate)
# affiche: True

+ 0
- 98
cours/source/04-code-source/index.rst View File

@@ -1,98 +0,0 @@
Chapitre 4 - code source
========================

Non persistance des variables
------------------------------

.. code-block:: console

$ python3
>>> a = 2
>>> quit()
```

.. code-block:: console

$ python3
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined


Du code dans un fichier
-----------------------

Aussi appelé: "code source", ou "source".

L'essence du logiciel libre :)



Installation d'un éditeur de texte simple
------------------------------------------

* Linux; ``gedit``, ``kate``, ...
* macOS: ``CotEditor``
* Windows: ``Notepad++``

J'insiste sur **simple**. Inutile d'installer un IDE pour le moment.


Configuration
-------------

* Police de caractères à chasse fixe
* Indentation de *4 espaces*
* Remplacer tabulation par des espaces
* Activer la coloration syntaxique



Notre premier fichier source
-----------------------------


Insérez le code suivant dans votre éditeur de texte

.. code-block:: python

# Affiche un message
print("Bonjour, monde")


Sauvegardez dans un fichier `bonjour.py` dans `Documents/e2l/python` par exemple


Lancer du code en ligne de commande
-----------------------------------


.. code-block:: console

cd Documents/e2l/python/
python3 bonjour.py
Bonjour, monde

* Les lignes commençant par dièse (``#``) ont été ignorées - ce sont des *commentaires*.
* ``print()`` affiche la valeur, comme dans le REPL.


Note importante
---------------

Vous avez juste besoin:

* d'un éditeur de texte
* de Python3 installé
* d'une ligne de commande

Pas la peine d'installer quoique ce soit de plus pour le moment


1. *Recopiez* le code affiché dans votre éditeur, à la suite du code
déjà écrit
2. Lancez le code depuis la ligne de commande
3. Réparez les erreurs éventuelles
4. Recommencez


+ 46
- 18
cours/source/05-flot-de-controle/01-flot-de-contrôle.rst View File

@@ -1,25 +1,36 @@
Flot de contrôle
================

L'essence de la programmation!
Pour l'instant, toutes les instructions que nous avons
écrites ont été exécutée une par une et dans l'ordre
d'apparition dans le code source.

Modifier l'ordre d'exécution de ces lignes s'appelle modifier le flot de
contrôle, et c'est l'essence de la programmation!


if
--
++

.. code-block:: python
On peut utiliser le mot ``if`` pour autoriser ou empécher
l'éxcution du code en-dessous::

a = 3
b = 4
if a == b:
print("a et b sont égaux")
print("on continue")
# affiche juste
# on continue

La 4ème ligne n'est pas éxécutée parce la condition
est fausse.

Notes:

* deux points à la fin de la ligne
* indentation après les deux points
* il y a le caractère ``:`` (deux points) à la fin de la ligne
* le code en-dessous du ``if`` commence par 4 espaces: on appelle
cela une *indentation*
* si la condition n'est pas vraie, rien ne se passe

Notez qu'on peut mettre uniquement une variable ou une valeur
@@ -27,14 +38,25 @@ après le if. Ceci ne fonctionne pas::

if a = 3:
print("a égale 3")
# affiche: SyntaxError

On parle aussi de "bloc" si plusieurs lignes sont identées::

et fait une erreur de syntaxe
a = 3
b = 4
if a == b:
# début du bloc
print("a et b sont égaux")
c = 2 * a
# fin du block
print("on continue")


if / else
---------

.. code-block::
On peut utiliser le mot ``else`` après un condition en ``if``
pour éxécutér un bloc si la condition est fausse::

a = 3
b = 4
@@ -42,52 +64,58 @@ if / else
print("a et b sont égaux")
else:
print("a et b sont différent")
# affiche: a et b sont différents


if / elif
---------

.. code-block::
On peut utiliser ``if``, ``elif`` et ``else`` pour enchaîner plusieurs
conditions::

age = 23
if age < 10:
print("inférieur à dix")
print("âge inférieur à dix")
elif 10 <= age < 20:
print("âge entre 10 et 20")
elif 20 <= age < 40:
print("âge entre 20 et 40")
else:
print("âge supérieur à 40")

On peut mettre autont de `elif` qu'on veut!
Le derier `else` s'éxécute en dernier
# affiche: âge entre 20 et 40


while
-----

Répéter tant qu'une condition est vraie::
On peut utiliser ``while`` pour répéter un bloc tant qu'une condition
est vraie::

i = 0
while i < 3:
print(i)
i = i + 1

.. code-block:: console
.. code-block:: text

0
1
2

Notez que la variable ``i`` passe par plusieurs valeurs différentes.

Notre première boucle infinie
-----------------------------
Boucle infinie
--------------

.. code-block::
On parle de *boucle infinie* si la condition ne devient jamais fausse::

while True:
print("spam!")

CTRL-C pour interrompre
Dans ce cas, il faut appuyer sur ``CTRL-C`` pour interrompre
le programme.

Notez ici qu'on a mis directement la valeur ``True``, et non une comparaison.


Combiner while et if


+ 28
- 13
cours/source/06-fonctions/01-functions.rst View File

@@ -11,15 +11,23 @@ Définition::


* avec `def`
* avec un `:` à la fin et un *bloc indenté* (appelé le "corps")
* avec un `:` à la fin et un *bloc indenté* (appelé *le corps de la fonction*).

Appel::

>>> dire_bonjour()
Bonjour
dire_bonjour()

* avec le nom de la fonction et des parenthèses

Example complet::

def dire_bonjour():
print("Bonjour")

bonjour()
# Affiche: bonjour'


Le pouvoir des fonctions
------------------------

@@ -35,6 +43,7 @@ programmation.


Fonction avec un argument
--------------------------

Définition: avec l'argument à l'intérieur des parenthèses::

@@ -43,17 +52,10 @@ Définition: avec l'argument à l'intérieur des parenthèses::

Appel: en passant une variable ou une valeur dans les parenthèses::

>>> dire_bonjour("Germaine")
Bonjour Germaine

>>> prénom_de_charlotte = "Charlotte"
>>> dire_bonjour(prénom_de_charlotte)
Bonjour Charlotte

Exécution d'une fonction
------------------------
dire_bonjour("Germaine")

C'est exatement comme si on assignait les arguments de la fonction avant d'éxécuter le code
L'éxécution de l'appel à une foctionne exactement comme si on assignait
les arguments de la fonction avant d'éxécuter le code
dans le corps::

# Ceci:
@@ -65,3 +67,16 @@ dans le corps::

# Lui-même équivalent à:
print("Bonjour " + "Dimitri")

Example complet::


def dire_bonjour(prénom):
print("Bonjour " + prénom)
dire_bonjour("Germaine")
# affiche: Bonjour Germaine

prénom_de_charlotte = "Charlotte"
dire_bonjour(prénom_de_charlotte)
# affiche: Bonjour Charlotte


+ 3
- 3
cours/source/06-fonctions/02-portée-des-variables.rst View File

@@ -22,8 +22,8 @@ Les variables en dehors des fonctions sont disponibles partout::
Une variable peut avoir en "cacher" une autre si elle a une portée différente::

def dire_bonjour(prénom):
print("Bonjour " + prénom) # portée: uniquement dans
# le corps dire_bonjour
print("Bonjour " + prénom) # portée: uniquement dans
# le corps dire_bonjour

prénom = "Dimitri" # portée: dans tout le programme
prénom = "Dimitri" # portée: dans tout le programme
dire_bonjour(prénom) # Ok

+ 8
- 6
cours/source/06-fonctions/04-par-défaut.rst View File

@@ -11,9 +11,11 @@ On peut aussi mettre des valeurs par défaut::

Appel::

>>> dire_bonjour("Thomas", enthousiaste=True)
Bonjour Thomas!
>>> dire_bonjour("Thomas", enthousiaste=False)
Bonjour Thomas
>>> dire_bonjour("Thomas")
Bonjour Thomas
dire_bonjour("Thomas", enthousiaste=True)
# affiche: Bonjour Thomas!

dire_bonjour("Thomas", enthousiaste=False)
# affiche: Bonjour Thomas

dire_bonjour("Thomas")
# affiche: Bonjour Thomas

+ 19
- 7
cours/source/06-fonctions/05-fonctions-natives.rst View File

@@ -18,19 +18,31 @@ On peut passer autant d'arguments qu'on veut à ``print`` et:
* Il les sépare par des espaces
* Ajoute un retour à la ligne à la fin::

>>> prénom = "Charlotte"
prénom = "Charlotte"
print("Bonjour", pŕenom)
print("Ça va ?")

.. code-block:: text

Bonjour Charlotte
Ça va ?


On peut demander à `print` de changer son séparateur::

>>> a = "chauve"
>>> b = "souris"
>>> print(a, b, sep="-")
a = "chauve"
b = "souris"
print(a, b, sep="-")

.. code-block:: text

chauve-souris

Ou de changer le caractère de fin::

>>> print("Ceci tient", end="")
>>> print("sur une seule ligne")
Ceci tient sur une seule ligne
print("Ceci tient", end="")
print("sur une seule ligne")

.. code-block:: text

Ceci tient sur une seule ligne

+ 10
- 2
cours/source/06-fonctions/06-return.rst View File

@@ -26,9 +26,17 @@ corps de la fonction::
return
print("Heureux de faire votre connaissance")

>>> dire_bonjour("Dimitri", première_fois=True)
dire_bonjour("Dimitri", première_fois=True)

.. code-block:: text

Bonjour Dimitri
Heureux de faire votre connaissance

>>> dire_bonjour("Dimitri", première_fois=False)
.. code-block:: python

dire_bonjour("Dimitri", première_fois=False)

.. code-block:: text

Bonjour Dimitri

+ 87
- 44
cours/source/07-listes/index.rst View File

@@ -33,41 +33,48 @@ Connaître la taille d'une liste

Avec ``len()`` - encore une fonction native::

>>> liste_vide = []
>>> len(liste_vide)
0
>>> trois_entiers = [1, 2, 3]
>>> len(trois_entiers)
3
liste_vide = []
taille = len(liste_vide)
print(taille)
# affiche: 0

trois_entiers = [1, 2, 3]
taille = len(trois_entiers)
print(taille)
# affiche: 3

Concaténation de listes
-----------------------

Avec ``+``::

>>> prénoms = ["Alice", "Bob"]
>>> prénoms += ["Charlie", "Eve"]
>>> prénoms
['Alice', 'Bob', "Charlie", 'Eve']
prénoms = ["Alice", "Bob"]
prénoms += ["Charlie", "Eve"]
print(prénoms)
# affiche: ['Alice', 'Bob', "Charlie", 'Eve']

On ne peut concaténer des listes que avec d'autres listes::

>>> scores = [1, 2, 3]
>>> scores += 4 # TypeError
>>> scores += [4] # OK
scores = [1, 2, 3]
scores += 4
# erreur

scores += [4]
print(scores)
# affiche: [1,2,3,4]

Test d'appartenance
-------------------

Avec ``in``::

>>> prénoms = ["Alice", "Bob"]
>>> "Alice" in prénoms
True
prénoms = ["Alice", "Bob"]
print("Alice" in prénoms)
# affiche: True

>>> prénoms = ["Alice", "Bob"]
>>> "Charlie" in prénoms
False
prénoms = ["Alice", "Bob"]
print("Charlie" in prénoms)
# affiche: False

Itérer sur les élements d'une liste
------------------------------------
@@ -80,35 +87,43 @@ Avec ``for ... in``::
# élément de la liste
print("Bonjour", prénom)

.. code-block:: text

Bonjour Alice
Bonjour Bob
Bonjour Charlie

## Indéxer une liste
Indéxer une liste
------------------

* Avec `[]` et un entier
* Avec ``[]`` et un entier

* Les index valides vont de 0 à `n-1` où `n` est la
* Les index valides vont de 0 à ``n-1`` où ``n`` est la
taille de la liste::

>>> fruits = ["pomme", "orange", "poire"]
>>> fruits[0]
"pomme"
>>> fruits[1]
"orange"
>>> list[2]
"poire"
>>> fruits[3] # IndexError
fruits = ["pomme", "orange", "poire"]

print(fruits[0])
# affiche: "pomme"

print(fruits[1])
# affiche: "orange"

print(list[2])
# affiche: "poire"

fruits[3]
# erreur: IndexError

Modifier une liste
-------------------

Encore une assignation::

>>> fruits = ["pomme", "orange", "poire"]
>>> fruits[0] = "abricot"
>>> fruits
["abricot", "orange", "poire"]
fruits = ["pomme", "orange", "poire"]
fruits[0] = "abricot"
print(fruits)
# affiche: ["abricot", "orange", "poire"]

Les strings sont aussi des listes (presque)
--------------------------------------------
@@ -128,17 +143,45 @@ On peut itérer sur les caractères d'une string::

On peut tester si un caractère est présent::

>>> "e" in "vache"
True
>>> "x" in "vache"
False
print("e" in "vache")
# affiche: True

print(x" in "vache")
# affiche: False


Mais on neut peut pas modifier une string::

>>> prénom = "Charlotte"
>>> prénom[0]
"C"
>>> prénom[3]
"r"
>>> prénom[0] = "X" # TypeError
prénom = "Charlotte"
l = prénom[0]
print(l)
# affiche: "C"

l = prénom[3]
print(l)
# affiche: "r"

prénom[0] = "X"
# erreur: TypeError


Falsy et truthy
----------------


En réalité on peut mettre autre chose qu'une comparaison ou une variable booléenne après le if.

Si on met une liste vide, ``if`` se comportera comme si on avait mis une valeur fausse, et si
la liste n'est pas vide , ``if`` se comportera comme si on avait mis une valeur vraie.::

ma_liste = [1, 2, 3]
if ma_liste:
print("ma_liste n'est pas vide")
# affiche: ma_liste n'est pas vide

mon_autre_liste = []
if not mon_autre_liste:
print("mon_autre_liste est vide")
# affiche: mon_autre_liste est vide

On dit que les listes vides sont *Falsy* et les listes non-vides *Truthy*

+ 31
- 42
cours/source/08-none-et-pass/01-none.rst View File

@@ -8,17 +8,6 @@ Définition

Un peu comme ``True`` et ``False`` qui sont deux valeurs qui servent à représenter tous les booléens.

Représenter l'absence
----------------------

L'interpréteur intéractif n'affiche rien quand la valeur est None::

>>> a = 42
>>> a
42
>>> b = None
>>> b

Retourner None
----------------

@@ -26,11 +15,12 @@ En réalité, *toutes* les fonctions pythons retournent *quelque chose*, même q
elle ne contiennent pas le mot-clé ``return``.::

def ne_renvoie_rien():
print("je ne fais qu'afficher quelque chose")
x = 2

>>> resultat = ne_renvoie_rien()
"je ne fais qu'afficher quelque chose"
>>> resultat
resultat = ne_renvoie_rien()

print(resultat)
# affiche: None

Opérations avec None
---------------------
@@ -38,17 +28,26 @@ Opérations avec None
La plupart des fonctions que nous avons vues échouent si on leur passe ``None``
en argument::

>>> len(None)
TypeError: object of type 'NoneType' has no len()
>>> None < 3
TypeError: '<' not supported between instances of
'NoneType' and 'int'
>>> int(None)
TypeError: int() argument must be a string,
a bytes-like object or a number,
not 'NoneType'
>>> str(None)
'None'
x = len(None)
# erreur: TypeError

x = None < 3
# erreur: TypeError

x = int(None)
# erreur: TypeError

Mais ``str`` fonctionne::

x = str(None)
print(x)
# affiche: 'None'

On peut vérifier si une variable vaut ``None`` avec ``is None``::

x = ne_renvoie_rien()
print(x is None)
# affiche: True

Example d'utilisation
----------------------
@@ -61,20 +60,10 @@ Example d'utilisation
return element
return None

>>> trouve_dans_liste(2, [1, 2, 3])
2
>>> trouve_dans_liste(False, [True, False])
False
>>> trouve_dans_liste(1, [3, 4])


None est Falsy, et on peut vérifier si une variable vaut ``None`` avec ``is None``::
x = trouve_dans_liste(2, [1, 2, 3])
print(x)
# affiche: 2

# hypothèse: `ma_valeur` n'est pas None
mon_element = trouve_dans_liste(ma_valeur, ma_liste)
if mon_element is None:
print("élément absent de la liste")
if not mon_element:
# Peut-être que l'élément n'était pas dans la liste,
# ou peut-être y était-il, mais avec une valeur falsy
...
x = trouve_dans_liste(1, [3, 4])
print(x)
# affiche: None

+ 54
- 92
cours/source/09-dictionnaires/index.rst View File

@@ -31,49 +31,57 @@ Accès aux valeurs

Avec ``[]``, comme pour les listes, mais avec une *clé* à la place d'un *index*::

>>> scores = {"john": 10, "bob": 42}
>>> scores["john"]
10
>>> scores["bob"]
42
>>> scores["charlie"]
KeyError
scores = {"john": 10, "bob": 42}

print(scores["john"])
# affiche: 10

print(scores["bob"])
# affiche: 42

print(scores["charlie"])
# erreur: KeyError

Test d'appartenance
---------------------

Avec ``in``, comme le listes::

>>> scores = {"john": 10, "bob": 42}
>>> "charlie" in scores
False
scores = {"john": 10, "bob": 42}
print("charlie" in scores)
# affiche: False

Modifier la valeur d'une clé
-----------------------------

Comme pour les listes, avec une assignation::

>>> scores = {"john": 10, "bob": 42}
>>> scores["john"] = 20
>>> scores
{"john": 20, "bob": 42}
scores = {"john": 10, "bob": 42}
scores["john"] = 20
print(scores)
# affiche: {"john": 20, "bob": 42}

Créer une nouvelle clé
-----------------------

Même méchanisme que pour la modification des clés existantes::
Même mécanisme que pour la modification des clés existantes::

scores = {"john": 10, "bob": 42}
scores["charlie"] = 30
print(scores)
# affiche: {"john": 20, "bob": 42, "charlie": 30}

>>> scores = {"john": 10, "bob": 42}
>>> scores["charlie"] = 30
>>> scores
{"john": 20, "bob": 42, "charlie": 30}
*rappel*: ceci ne fonctionne pas avec les listes: on ne peut
pas "créer" de nouveaux éléments dans la liste juste
avec un index::

*rappel*: ceci ne fonctionne pas avec les listes!::
>>> ma_liste = ["a", "b"]
>>> ma_liste[1] = "c" # ok
["a", "c"]
>>> ma_liste[3] = "d"
IndexError
ma_liste = ["a", "b"]
ma_liste[1] = "c"
print(ma_liste)
# affiche: ["a", "c"]

ma_liste[3] = "d"
# erreur: IndexError

Itérer sur les clés
-------------------
@@ -84,8 +92,14 @@ Avec ``for ... in ...``, comme pour les listes::
for nom in scores:
# `nom` est assigné à "john" puis "bob"
score_associé_au_nom = scores[nom]
# score_associé_au_nom est assigné à '10' puis '42'
print(nom, score_associé_au_nom)

.. code-block::

john 10
bob 42

del
---

@@ -94,83 +108,31 @@ Détruire une clé

Avec ``del`` - un nouveau mot-clé::

>>> scores = {"john": 10, "bob": 42}
>>> del scores["bob"]
>>> scores
{"john": 10}
scores = {"john": 10, "bob": 42}
del scores["bob"]
print(scores)
# affiche: {"john": 10}

Détruire un élément d'une liste
++++++++++++++++++++++++++++++++

Aussi avec ``del``::

>>> fruits = ["pomme", "banane", "poire"]
>>> del fruits[1]
>>> fruits
["pomme", "poire"]
fruits = ["pomme", "banane", "poire"]
del fruits[1]
print(fruits)
# affiche: ["pomme", "poire"]

Détruire une variable
+++++++++++++++++++++

Encore et toujours ``del``::

>>> mon_entier = 42
>>> mon_entier += 3
>>> mon_entier
45
>>> del mon_entier
>>> mon_entier == 45
NameError: name 'mon_entier' is not defined

Des dictionnaires partout
---------------------------

Les variables globales d'un programme Python sont dans un dictionnaire,
accessible avec la fonction native `globals()`::

$ python3
>>> globals()
{
...
'__doc__': None,
'__name__': '__main__',
...
}

On reparlera de `__doc__` et `__name__` un autre jour ...::


$ python3
>>> a = 42
>>> globals()
{
...
'__doc__': None,
'__name__': '__main__',
...
'a': 42
}
```

.. code-block::

python
$ python3
>>> a = 42
>>> del globals()["a"]
>>> a
NameError: name 'a' is not defined


On peut accéder aux variables locales d'une fonction avec ``locals()``::

def ma_fonction():
a = 42
b = 3
c = a + b
print(locals())

>>> ma_fonction()
{'a': 42, 'b': 3, 'c': 45}
mon_entier = 42
mon_entier += 3
print(mon_entier)
# affiche: 45

En revanche, il n'est pas conseillé de modifier le dictionaire renvoyé par ``locals()`` ...
del mon_entier
mon_entier += 1
# erreur: NameError

+ 40
- 34
cours/source/10-tuples/index.rst View File

@@ -35,10 +35,11 @@ Accès
Avec ``[]`` et l'index de l'élément dans le tuple::

mon_tuple = (42, "bonjour")
mon_tuple[0]
42
mon_tuple[1]
"bonjour"
print(mon_tuple[0])
# affiche: 42

print(mon_tuple[1])
# affiche: "bonjour"

Modification
------------
@@ -47,7 +48,7 @@ Interdit::

mon_tuple = (42, "bonjour")
mon_tuple[0] = 44
TypeError: 'tuple' object does not support item assignment
# erreur: TypeError: 'tuple' object does not support item assignment


Test d'appartenance
@@ -55,26 +56,28 @@ Test d'appartenance

Avec ``in``:

>>> mon_tuple = (42, 14)
>>> 42 in mon_tuple
True
mon_tuple = (42, 14)
print(42 in mon_tuple)
# affiche: True

print(14 in mon_tuple)
# affiche: True

>>> 14 in mon_tuple
True
>>> 13 in mon_tuple
False
print(13 in mon_tuple)
# affiche: False

Déstructuration
----------------

Créer plusieurs variables en une seule ligne::

>>> couple = ("Batman", "Robin")
>>> héros, side_kick = couple
>>> héros
'Batman'
>>> side_kick
'Robin'
couple = ("Batman", "Robin")
héros, side_kick = couple
print(héros)
# affiche: Batman

print(side_kick)
# affiche: Robin


Quelques erreurs classiques
@@ -82,15 +85,15 @@ Quelques erreurs classiques

.. code-block:: python

>>> héros, side_kick, ennemi = couple
ValueError (3 != 2)
héros, side_kick, ennemi = couple
# erreur: ValueError (3 != 2)

>>> (héros,) = couple
ValueError (1 != 2)
(héros,) = couple
# erreur: ValueError (1 != 2)

# Gare à la virgule:
>>> héros, = couple
ValueError (1 != 2)
héros, = couple
# erreur: ValueError (1 != 2)

Pièges
------
@@ -110,16 +113,19 @@ Pièges

On peut aussi déstructurer des listes::

>>> fruits = ["pomme", "banane", "orange"]
>>> premier, deuxième, troisième = fruits
>>> premier
"pomme"
>>> deuxième
"banane"
>>> troisième
"orange"
fruits = ["pomme", "banane", "orange"]
premier, deuxième, troisième = fruits

print(premier)
# affiche: pomme

print(deuxième)
# affiche: banane

print(troisième)
# affiche: orange

On dit aussi: unpacking
On dit aussi: *unpacking*

Utilisations des tuples
------------------------
@@ -147,6 +153,6 @@ Pour retourner plusieurs valeurs::

v, c = tire_carte()
print(v, "de", c)
# 10 de trèfle
# affiche: 10 de trèfle

Ce n'est pas une nouvelle syntaxe, juste de la manipulation de tuples!

+ 37
- 35
cours/source/11-classes-01/index.rst View File

@@ -105,14 +105,14 @@ Le code suivant fait exactement la même chose, mais avec une ligne de moins::

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

>>> mon_instance = MaClasse()
mon_instance = MaClasse()

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

# Accés à l'attribut `x` dans `mon_instance`
>>> mon_instance.mon_attribut
42
print(mon_instance.mon_attribut)
# affiche: 42

Méthodes - définition
----------------------
@@ -135,12 +135,14 @@ la classe::
class MaClasse:
def ma_méthode(self):
return 42
>>> ma_méthode()
Erreur

>>> mon_instance = MaClasse()
>>> mon_instance.ma_méthode()
42
ma_méthode()
# erreur: NameError

mon_instance = MaClasse()
résultat = mon_instance.ma_méthode()
print(résultat)
# affiche: 42

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

@@ -158,10 +160,10 @@ On peut le voir en utilisant des attributs::
print(self.x)


>>> mon_instance = MaClasse()
>>> mon_instance.x = 42
>>> mon_instance.affiche_attribut_x()
42
mon_instance = MaClasse()
mon_instance.x = 42
mon_instance.affiche_attribut_x()
# Affiche: 42

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

@@ -171,13 +173,13 @@ On peut aussi *créer* des attributs dans une méthode::
def affiche_attribut_x(self):
print(self.x)

>>> mon_instance = MaClasse()
>>> mon_instance.affiche_attribut_x()
# Erreur: `mon_instance` n'a pas d'attribut `x`
mon_instance = MaClasse()
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
mon_instance.crée_attribut_x()
mon_instance.affiche_attribut_x()
# affiche: 42

Les méthodes peuveunt aussi prendre plusieurs arguments, en plus de ``self`` - mais ``self`` doit
toujours être le premier argument.
@@ -192,10 +194,10 @@ Par example, pour créer un attribut avec une certaine valeur::
def affiche_attribut_x(self);
print(self.x)

>>> mon_instance = MaClasse()
>>> mon_instance.crée_attribut_x(42)
>>> mon_instance.affiche_attribut_x()
42
mon_instance = MaClasse()
mon_instance.crée_attribut_x(42)
mon_instance.affiche_attribut_x()
# affiche: 42

Méthodes appelant d'autres méthodes
------------------------------------
@@ -217,8 +219,8 @@ les unes les autres::
print("fin de la méthode 2")


>>> mon_instance = MaClasse()
>>> mon_instance.méthode_2()
mon_instance = MaClasse()
mon_instance.méthode_2()

.. code-block::

@@ -246,13 +248,13 @@ On utilise souvent ``__init__`` pour créer des attributs::
self.x = 1
self.y = 2

>>> mon_instance = MaClasse()
mon_instance = MaClasse()

# __init__ est appelée automatiquement!
>>> mon_instance.x
1
>>> mon_instance.y
2
print(mon_instance.x)
# affiche: 1
print(mon_instance.y)
# affiche: 2

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

@@ -264,11 +266,11 @@ On prend souvent les *valeurs* des attributs à créer en arguments de la métho
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 = MaClasse(3, 4)
>>> mon_instance.x
3
>>> mon_instance.y
4
mon_instance = MaClasse(3, 4)
print(mon_instance.x)
# affiche: 3
print(mon_instance.y)
# affiche: 4

.. note::



+ 34
- 55
cours/source/12-modules-01/index.rst View File

@@ -16,27 +16,27 @@ Importer un module

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

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

# 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::
Comme un fichier = un module, on vient de crée un module ``bonjour`` contenant une variable ``a``.

$ python
>>> import bonjour
>>> bonjour.a
42
Si maintenant on crée un fichier ``salutations.py`` dans le même répertoire,
on peut accéder à cette variable en *important* le module::

Notez que pour que cela fonctionne:
# Dans salutations.py
import bonjour
print(bonjour.a)
# affiche: 42

* Le nom du module est écrit directement, ce n'est *pas* une

.. note::

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é
@@ -44,52 +44,26 @@ un *attribut* du module `bonjour` lorsque `bonjour` a été importé

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

# toujours dans bonjour.py
# 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``::

>>> 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::

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

On peut aussi modifier les valeurs des attributs::

>>> import bonjour
>>> bonjour.a
42
>>> bonjour.a = 36
>>> bonjour.a
36
On peut appeler la fonction ``dire_bonjour`` depuis ``salutations.py``
en utilisant l'attribut ``dire_bonjour`` du module ``bonjour``::

# Dans salutations.py
import bonjour
bonjour.dire_bonjour()
# affiche: Bonjour!

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.
Il est important de noter que:

* **tout** le code à l'intérieur d'un module est éxécuté lors du premier import
* mais il 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
@@ -97,15 +71,20 @@ de variables::

# Dans bonjour.py
print("Je suis le module bonjour et tu viens de m’importer")
def dire_bonjour():
....

.. code-block:: python

# Dans salutation.py
import bonjour
# affiche: Je suis le module bonjour et tu viens de m’importer

>>> import bonjour
Je suis le module foo et tu viens de m’importer
>>> import bonjour
<rien>
import bojour
# n'affiche rien

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

a bibliothèque standard
La bibliothèque standard
------------------------

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


cours/source/13-classes-02/02-couplage.rst → cours/source/13-classes-02/01-couplage.rst View File

@@ -18,16 +18,17 @@ On peut utiliser pour cela deux classes: `Chat` et `Humain`::
def __init__(self, nom):
self.nom = nom

>>> chat = Chat("Monsieur Moustaches")
>>> chat.nom
'Monsieur Moustaches'
chat = Chat("Monsieur Moustaches")
prin(chat.nom)
# affiche: Monsieur Moustaches

class Humain:
def __init__(self, prénom):
self.prénom = prénom
>>> alice = Humain(prénom="Alice")
>>> alice.prénom
"Alice"

alice = Humain(prénom="Alice")
print(alice.prénom)
# affiche: Alice

Maintenant on veut que les humains puissent adopter des chats.
Pour cela, on peut rajouter la méthode ``adopte`` dans la classe
@@ -43,10 +44,10 @@ classe ``Chat``::
def adopte(self, chat):
print(self.prénom, "adopte un chat")

>>> boule_de_poils = Chat("Boule de Poils")
>>> alice = Humain("Alice")
>>> alice.adopte(boule_de_poils)
"Alice adopte un chat"
boule_de_poils = Chat("Boule de Poils")
alice = Humain("Alice")
alice.adopte(boule_de_poils)
# affiche: "Alice adopte un chat"

On peut accéder au nom du chat depuis la méthode ``adopte``,
en utilisant la syntaxe ``nom.attribut`` vue précédemment::
@@ -58,10 +59,10 @@ en utilisant la syntaxe ``nom.attribut`` vue précédemment::
def adopte(self, chat):
print(self.prénom, "adopte", chat.nom)

>>> boule_de_poils = Chat("Boule de Poils")
>>> alice = Humain("Alice")
>>> alice.adopte(boule_de_poils)
"Alice adopte Boule de Poils"
boule_de_poils = Chat("Boule de Poils")
alice = Humain("Alice")
alice.adopte(boule_de_poils)
# affiche: Alice adopte Boule de Poils

Couplage
--------

+ 0
- 176
cours/source/13-classes-02/01-rappels.rst View File

@@ -1,176 +0,0 @@
Rappels
=======

// TODO: drop?

.. note::

ceci est surtout un rappel du chapitre 11. N'hésitez pas à vous y
reporter si les exemples de code ne vous paraissent pas clairs.


Classes vides
-------------

Définition::

class MaClasse:
pass

Instanciation::

instance_1 = MaClasse()

Attributs
---------

Un attribut est une variable *à l'intérieur* d'autre chose (par exemple une instance de classe).

La syntaxe consiste en l'instance à gauche et l'attribut à droite après un point::

>>> mon_instance = MaClasse()
# création de l'attribut `x` dans mon_instance:
>>> mon_instance.x = 42
# accès à l'attribut `x` dans mon_instance:
>>> mon_instance.x
42

Méthodes
--------

Une méthode est une fonction définie à l'intérieur d'une classe:

Définition::

class MaClasse:
def ma_méthode(self):
return 42

Les méthodes sont des attributs des instances de classes::

class MaClasse:
def ma_méthode(self):
return 42
>>> ma_méthode()
Erreur
>>> mon_instance = MaClasse()
>>> mon_instance.ma_méthode()
42


self
----

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

class MaClasse:
def affiche_attribut_x(self):
print(self.x)

>>> mon_instance = MaClasse()
>>> mon_instance.x = 42
>>> mon_instance.affiche_attribut_x()
42

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

class MaClasse:
def crée_attribut_x(self):
self.x = 42
def affiche_attribut_x(self):
print(self.x)

>>> mon_instance = MaClasse()
>>> 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

Méthodes avec arguments
------------------------

.. code-block::

class MaClasse
def crée_attribut_x(self, valeur_de_x):
self.x = valeur_de_x

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

>>> mon_instance = MaClasse()
>>> mon_instance.crée_attribut_x(42)
>>> mon_instance.affiche_attribut_x()
42

Méthodes appelant d'autres méthodes
------------------------------------

.. code-block::

class MaClasse:
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")


>>> mon_instance = MaClasse()
>>> mon_instance.méthode_2()

.. code-block::

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

Constructeur sans arguments
---------------------------

Un constructeur en Python désigne la méthode nomée ``__init__``,
quand celle-ci existe.

La méthode ``__init__`` est appelée automatiquement quand la
classe est instanciée::

class MaClasse:
def __init__(self):
self.x = 1
self.y = 2

>>> mon_instance = MaClasse()
>>> mon_instance.x
1
>>> mon_instance.y
2

Constructeur avec arguments
----------------------------

La méthode ``__init__`` peut avoir des arguments,
dans ce cas, ceux ci doivent être fournis
lors de l'instanciation::

class MaClasse:
def __init__(self, x, y):
self.x = x
self.y = y

>>> mon_instance = MaClasse(3, 4)
>>> mon_instance.x
3

>>> mon_instance.y
4

cours/source/13-classes-02/03-composition.rst → cours/source/13-classes-02/02-composition.rst View File

@@ -10,20 +10,26 @@ Une classe à l'intérieur d'une autre classe.
Dépendances entre fonctions
-----------------------------

Exemple: on veut dessiner un sapin dans le terminal::
Exemple ::

def main():
largeur = demander_largeur()
dessine_sapin(largeur)
def calcule_x():
...
# du code ici

main()
def fait_un_truc_avec_x(x):
...
# du code ici

x = calcule_x()
fait_un_truc_avec_x(x)

On voit que la fonction ``dessine_sapin()`` prend un argument ``largeur``, qui est retourné
par la fonction ``demander_largeur()``.

``dessine_sapin()`` doit donc être appelée *après* ``demander_largeur()``. On dit que ``dessine_sapin()``
_dépend_ de ``demander_largeur()``.

On voit que la fonction ``fait_un_truc_avec_x()`` prend un argument ``x``, qui est retourné
par la fonction ``calcule_x()``.

``fait_un_truc_avec_x()`` doit donc être appelée *après* ``calcule_x()``. On dit que ``fait_un_truc_avec_x()``
*dépend* de ``calcule_x()``.

Dépendances entre classes
-------------------------
@@ -39,8 +45,8 @@ Revoyons la classe Chat::
Comme le constructeur de la classe Chat prend un nom en argument, il est impossible de construire
des chats sans nom::

>>> chat = Chat()
TypeError: __init__() missing 1 required positional argument: 'nom'
chat = Chat()
# erreur: TypeError: __init__() missing 1 required positional argument: 'nom'

De la même façon, si on veut que tous les enfants aient un chat (pourquoi pas, après tout), on peut
avoir une classe Enfant, dont le constructeur prend une instance de chat en plus du prénom::
@@ -50,11 +56,11 @@ avoir une classe Enfant, dont le constructeur prend une instance de chat en plus
self.prénom = prénom
self.chat = chat

>>> alice = Enfant("Alice")
TypeError: __init__() missing 1 required positional argument: 'chat'
alice = Enfant("Alice")
# erreur: TypeError: __init__() missing 1 required positional argument: 'chat'

>>> boule_de_poils = Chat("Boule de Poils")
>>> alice = Enfant("Alice", boule_de_poils)
boule_de_poils = Chat("Boule de Poils")
alice = Enfant("Alice", boule_de_poils)
# OK!

Utilisation de la composition
@@ -78,9 +84,9 @@ et ``ronronne()`` dans la classe chat::
self.ronronne()


>>> boule_de_poils = Chat("Boule de Poils")
>>> boule_de_poils.caresse()
Boule de Poils fait "prrrrr"
boule_de_poils = Chat("Boule de Poils")
boule_de_poils.caresse()
# affiche: Boule de Poils fait "prrrrr"

Ensuite, on peut rajouter la méthode ``console()`` dans la classe Enfant,
qui va:
@@ -95,11 +101,11 @@ qui va:
def console(self):
self.chat.caresse()

>>> boule_de_poils = Chat("Boule de Poils")
>>> alice = Enfant("Alice", boule_de_poils)
boule_de_poils = Chat("Boule de Poils")
alice = Enfant("Alice", boule_de_poils)
# Alice est triste, on la console
>>> alice.console()
Boule de Poils fait "prrrrr"
alice.console()
# affiche: Boule de Poils fait "prrrrr"
# Alice est consolée :)

On dit parfois qu'on a *délégué* l'implémentation de la méthode ``console()`` de la classe Enfant

+ 2
- 3
cours/source/13-classes-02/index.rst View File

@@ -4,6 +4,5 @@ Chapitre 13 - Classes (2ème partie)
.. toctree::
:maxdepth: 1

01-rappels
02-couplage
03-composition
01-couplage
02-composition

+ 1
- 1
cours/source/14-bibliothèques-01/02-sys.path.rst View File

@@ -4,7 +4,7 @@ sys.path
En Python, il existe une variable ``path`` prédéfinie dans le module ``sys`` qui fonctionne de manière similaire
à la variable d'environnement ``PATH``.

Si j'essaye de l'afficher sur ma machine, voici ce que j'obtiens:
Si j'essaye de l'afficher sur ma machine, voici ce que j'obtiens::

import sys
print(sys.path)


+ 8
- 5
cours/source/15-fichiers-et-données-binaires/01-données-binaires.rst View File

@@ -147,6 +147,9 @@ On peut aussi interpréter des octets comme du texte - c'est la table ASCII

.. image:: ../img/ascii-table.png

La table se lit ainsi: si on veut connaître la suite de 0 et de 1 qui correspond à `B`: on lit
les 3 premiers bits de haut en bas sur la colonne: `100`, puis les 4 bits sur la ligne: `0010`.
Du coup 'B' en s'écrit en 7 bits: `1000010`, soit 66 en décimal, et 42 en héxadécimal

ASCII - remarques
-----------------
@@ -155,20 +158,20 @@ ASCII - remarques
* Le A est pour American
* Ça sert à *envoyer* du texte sur des terminaux d'où les "caractères" non-imprimables dans la liste
* Mais c'est une convention *très* utilisée
* Techniquement, on n'a besoin que de 7 bits, mais on préfère envoyer des octets
* Un message de 4 lettres ASCII sera souvent envoyé comme 4 octets (même si seulement 7 bits sont nécessaires)

Utiliser ASCII en Python
------------------------

Avec ``chr`` et ``ord``::

x = chr(98)
x = chr(0x42)
print(x)
# affiche: b
# affiche: B

x = ord('a')
x = ord('B')
print(x)
# affiche: 97
# affiche: 66

Affichage des bytearrays en Python
----------------------------------


+ 1
- 1
cours/source/index.rst View File

@@ -20,7 +20,7 @@ remarques.
01-introduction/index
02-premiers-pas/index
03-variables-et-types/index
04-code-source/index
04-booléens/index
05-flot-de-controle/index
06-fonctions/index
07-listes/index