LP - Environnements de travail et éléments de syntaxe

LP - Environnements de travail et éléments de syntaxe #

Ce document est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 France.

  • Titre du document d’origine complet : Livret Pédagogique CodingUP
  • Auteurs : Laurent Signac, Emmanuel Laize, Freddy Lege, Caroline Tartary

Ce document est la première partie du Livret pédagogique, dans laquelle nous présentons succinctement la syntaxe du langage Python, ainsi que le langage visuel Blockly. Après la lecture de ce court document, une personne connaissant déjà un peu la programmation devrait avoir trouvé ses marques avec Python et disposera en outre de références vers des ressources lui permettant d’approfondir son apprentissage.

Le lecteur intéressé par un cours complet sur Python peut se reporter aux documents mentionnés sur cette page : Documentation

La seconde partie du document, intitulée Livret pédagogique : Activités propose, toujours avec le langage Python, des activités centrées autour de la résolution de problèmes et de défis.

Environnement de travail #

Le langage Python est un langage généraliste et interprété. Les interpréteurs Python sont disponibles pour beaucoup de plate formes : Unix, Window, Mac OS, mais aussi Android par exemple. Il existe essentiellement deux branches de l’interpréteur : la branche 2 et la branche 3. La branche 2 est maintenant obsolète, mais elle est encore largement utilisée, et certains documents, de plus en plus rare, utilisent la branche 2. Nous ne parlerons ici que de la branche 3.

Il existe des interpréteurs python en ligne, comme Repl.it.

Il est toutefois plus confortable d’installer Python sur son poste de travail : Télécharger Python

À l’heure où ces lignes sont revues, la version en cours est la 3.9.2. Sous linux, il est conseillé d’utiliser la version en cours de vote distribution (apt-get install python3, dnf install python3, pacman -S python…)

De son côté, le langage Blockly est entièrement visuel et s’utilise dans un navigateur Web en ligne : Blockly Code. Plusieurs démonstrations sont disponibles ici : https://blockly.games/

Mais on peut le télécharger pour l’installer sur son propre serveur Web (voir https://developers.google.com/blockly). Le principe est similaire à celui du langage Scratch, en un peu plus sobre (tester Scratch).

Documentations #

Blockly étant complètement graphique, on peut commencer à expérimenter sans documentation. En revanche, pour des langages écrits comme Python, il est nécessaire d’avoir un cours ou un tutoriel. Heureusement, il y en a beaucoup, dont certains sont d’excellente qualité. Une partie de ce livret contient des références vers des Documentations.

Éléments de syntaxe Python #

Dans cette (longue) partie, nous détaillons certains éléments de syntaxe essentiels en Python. Le lecteur est encouragé à expérimenter au fur et à mesure. L’accent est mis sur les difficultés qu’on peut rencontrer en venant d’un autre langage.

Variables #

En Python 3, les variables sont des références vers des objets. Beaucoup d’erreurs sont évitées en sachant cela. En particulier l’affectation :

>>> a = 5

a pour effet de :

  • créer ou récupérer l’objet 5
  • faire en sorte que a référence cet objet

Python supporte les objets listes (voir plus loin) :

>>> l1 = [4, 5, 6, 7]
>>> l2 = l1

Maintenant, l2 et l1 référencent la même liste :

>>> l1.append(10)
>>> print(l2)
==> [4, 5, 6, 7, 10]

Modifier l1 ou modifier l2, c’est la même chose, puisque les deux variables référencent la même liste. Mais attention :

>>> l1 = l1 + [40]
>>> print(l1)
[4, 5, 6, 7, 10, 40]
>>> print(l2)
[4, 5, 6, 7, 10]

En effet, l’opération l1 + [40] ne modifie pas la liste l1, mais crée une nouvelle liste, concaténation des listes l1 et de la liste [40]. L’affectation l1 = ... indique que l1 est une référence vers cette nouvelle liste. l1 et l2 mènent maintenant des vies séparées.

Python propose l’affectation multiple :

>>> a, b, c = 3, 5, 7
>>> print(b)
5

Pour compléter ce sujet, on pourra consulter :

Nombres #

Python peut gérer des entiers dont la taille n’est limitée que par la mémoire disponible. Le passage de la représentation entier machine en grands entiers est transparent :

>>> import math
>>> math.factorial(200)
    788657867364790503552363213932185062295135977687173263294742533244359449963403
    342920304284011984623904177212138919638830257642790242637105061926624952829931
    113462857270763317237396988943922445621451664240254033291864131227428294853277
    524242407573903240321257405579568660226031904170324062351700858796178922222789
    623703897374720000000000000000000000000000000000000000000000000

Les nombres à virgule (type float) suivent la norme IEEE 754, ce sont des nombres à virgule flottante double précision (identiques aux double du C).

Python possède aussi un type complex, un type Decimal (module decimal) proposant une autre représentation des nombres non entiers. En outre, le module numbers propose aussi le type Rational pour représenter les nombres rationnels ou le module fractions avec le type Fraction

Les opérations arithmétiques sont (presque) sans surprise :

  • * multiplication
  • + addition
  • - souscraction
  • / division non entière
  • //’ division entière
  • `%’ reste de la division entière
  • ** exponentiation

Chaînes de caractères #

Depuis la version 3 de Python, les chaînes de caractères sont par défaut des chaînes Unicode : tous les caractères du standard Unicode sont donc utilisables. Un littéral chaîne de caractères est représenté entre guillemets simples ou doubles (c’est la même chose). Les chaînes multilignes doivent êtres entourées de 3 guillemets simples ou doubles. On peut accéder à chaque caractère d’une chaîne en indiquant sa position dans la chaîne (le premier élément est numéroté 0) car une chaîne est une séquence. Une chaîne est donc aussi itérable, comme une liste, et toutes les méthodes applicables aux objets itérables sont donc applicables aux chaînes :

>>> s = "Ceci est une chaîne de caractères"
>>> s1 = """Et une autre
qui est multilignes."""
>>> s[16]
"î"
>>> len(s1) 
33

Conteneurs #

Les conteneurs sont probablement les objets qui participent grandement à l’expressivité d’un langage, on peut faire des choses assez complexes en peu de lignes, en utilisant les conteneurs et leurs outils associés.

Les conteneurs Python sont : les tuples (tuple), les listes (list), les dictionnaires (dict), les ensembles (set) et quelques autres…

Les listes (list) sont probablement les conteneurs les plus utilisés. On peut y ranger une collection ordonnée d’objets. Chaque élément de la liste est accessible par son indice (l’indice du premier élément est 0) :

>>> l = [4, 5, 6, [7, 8], 9]
>>> l[0]
4
>>> l[3]
[7, 8]
>>> l[3][1]
8
>>> l[3] = "bonjour"
>>> l
[4, 5, 6, 'bonjour', 9]
Il est toutefois conseillé d’utiliser les listes pour stocker des contenus homogènes : listes d’entiers, listes de chaînes, listes de tuples de chaines etc…

Les tuples (tuple) 1 sont presque identiques aux listes, mais ne sont pas modifiables (tous les types en Python appartiennent à une des deux catégories : modifiable/non modifiable (mutable/immutable) ), ce qui signifie qu’on ne peut pas modifier le contenu de l’objet. Pour ajouter un élément à un tuple, il faut donc créer un nouveau tuple contenant un élément de plus que le tuple d’origine. Un des éléments du tuple ne peut pas être modifié sans recréer le tuple. Les tuples sont délimités par des parenthèses (...). On accès aux éléments d’un tuple en indiquant la position avec des crochets [...] (le premier élément est numéroté 0, comme avec les chaînes).

>>> t = (5, 6, 7)
>>> t[1] 
6
>>> t[2] = 3 # Opération impossible
>>> s = t + (7, 8, 9)
>>> s
(4, 5, 6, 7, 8, 9)
Pour des informations complémentaires sur les types modifiables et non modifiables, on pourra consulter : Mutable and Immutable

Les dictionnaires (dict) permettent de représenter les collections non ordonnées d’objets accessibles par le biais d’une clé (ils s’apparentent aux tables de hachage et aux tableaux associatifs). Les dictionnaires sont modifiables :

>>> d = {"key1": 42, "nom": "Untel" , 10: 3}
>>> d["key1"] 
42
>>> d[10]
3
>>> d["nom"] = "Machin"
>>> d["nom"]
'Machin'

Les ensembles (set) permettent de représenter des collections d’objets non ordonnées, tous uniques. Dans les méthodes relatives aux ensembles, on trouve l’union, l’intersection, la différence symétrique… qui sont parfois très utiles. Les ensembles sont modifiables.

>>> s = {1, 4, 6, 4, 2, 5, 3, 2}
>>> s
{1, 2, 3, 4, 5, 6}
>>> s = s - {2,2,4,10} # Différence 
{1, 3, 5, 6}
Les autres conteneurs Python sont bytearray, dequeue (pour des piles et des files plus efficaces que ce qu’on obtient avec des listes), namedtuple (sorte d’équivalent des structures en C), ou le plus récent dataclass.

Tests et boucles #

Il va ici être question de blocs, et de petits programmes de quelques lignes. Dès qu’on doit entrer du code contenant des blocs, il est bien plus confortable de ne pas le faire dans le shell Python (bien que ce soit possible), mais plutôt avec un éditeur de code. Si vous avez installé Python sur votre machine, vous pouvez utiliser l’éditeur idle, généralement fourni avec Python. Dans ce qui suit, si le code est précédé du prompt >>>, il est fait pour être entré en ligne de commande (dans le shell). S’il n’y a pas le prompt, il est fait pour être entré dans l’éditeur et exécuté ensuite.

En ce qui concerne les tests, la syntaxe Python est faite pour ne pas être très surprenante :

n = int(input("Entrez un nombre entier "))
if n % 7 == 0:
    print(n, "est un multiple de 7")
else:
    print(n, "n'est pas un multiple de 7")

Dans ce qui précède, la première ligne (input) permet à l’utilisateur d’entrée une valeur qui est convertie en entier (int) avant d’être stockée dans n (on devrait dire avant d’être référencée par n).

Puis, si le reste de la division entière de ce nombre par 7 est 0, on affiche un message, sinon, on en affiche un autre. Notons les : qui annoncent un bloc d’instruction. Un bloc est délimité par une indentation (par 4 espaces si on suit les conventions Python) et se termine à l’endroit où l’indentation cesse. Le programme précédent contient donc 2 blocs indentés qui ne font qu’une ligne chacun. La prise en compte de l’indentation dans la syntaxe est un élément peu conventionnel de Python, qui déroute assez facilement les programmeurs venant d’un autre langage. Le programme suivant est par exemple syntaxiquement faux :

# Programme faux 
n = 12
if n % 7 == 0: 
    print("Le nombre ", n)
   print("est un multiple de 7")
else:
print(n, "n'est pas un multiple de 7")

La première erreur vient du bloc de 3 lignes dans le if dont l’indentation varie (précisément, l’indentation de la seconde ligne ne correspond si au bloc intérieur au if, ni au if lui même et c’est donc une erreur. La seconde erreur vient du bloc dans le else qui n’est pas indenté.

La boucle while est sans surprise :

a, b = 0, 1
while a < 200:
    a, b = b, a + b
    print(a)

On remarque qu’une boucle while attend un booléen, puis un bloc.

Les propositions dans un test ou une boucle peuvent être liées par les connecteurs logiques : and, or, not.

Les mots clés break et continue permettent respectivement d’arrêter la boucle ou de passer directement au tour de boucle suivant.

La boucle while peut se terminer par un bloc else, un peu déroutant, qui est exécuté après la boucle, sauf si on sort de celle-ci prématurément (par un break).

La boucle for permet d’itérer sur n’importe quel objet itérable. Son utilisation rend le code plus lisible, plus facile à comprendre, et souvent plus rapide. Voici quelques exemples :

for i in range(5):
    print(i)
print("---")
l = [3, 5, 7, 11, 13, 17]
for p in l:
  print(p)

d = {"nom": "Machin", "age": 35, "profession": "enseignant"}
for k, v in d.items():
    print("Clé    : ", k)
    print("Valeur : ", v)
    
s = ["a", "e", "i", "o", "u"]
for i, v in enumerate(s):
    print("Voyelle", i, ":", v)

Le code précédent produit :

0
1
2
3
4
---
3
5
7
11
13
17
Clé    :  nom
Valeur :  Machin
Clé    :  age
Valeur :  35
Clé    :  profession
Valeur :  enseignant
Voyelle 0 : a
Voyelle 1 : e
Voyelle 2 : i
Voyelle 3 : o
Voyelle 4 : u

Notons que range(5) qui est équivalent à range(0, 5) permet d’itérer sur les valeurs 0, 1, 2, 3 et 4 (et pas 5). On peut trouver ça un peu agaçant :confunded:…

Il existe bien d’autres méthodes qui permettent de facilement itérer des collections d’objets. Il n’est pas utile de toutes les connaître pour démarrer.

Fonctions #

Les fonctions sont définies par le mot clé def. Les premiers arguments sont positionnels, puis suivent les arguments nommés, et enfin un éventuel dictionnaire. Nous n’utiliserons que les arguments positionnels ici

La valeur renvoyée par la fonction est indiquée par le mot clé return qui quitte la fonction au moment de son exécution. En l’absence de return, une fonction renverra la valeur None.

import math
def combinaisons(n, p):
    if p > n or p < 0:
        return 0
    s = n
    for i in range(n - p + 1, n):
        s = s * i
    return s // math.factorial(p)

Une fois cette fonction connue de l’interpréteur (on peut l’entrer dans l’éditeur et l’envoyer à l’interpréteur), la fonction est utilisable ainsi :

>>> combinaisons(20, 3)
1140

Dans le code de la fonction notons :

  • l’importation du module de math, pour avoir la fonction factorielle (factorial) à disposition.
  • la sortie prématurée de la fonction qui renvoie 0 dans le cas où p ou n ne satisfont pas les bons critères
  • l’utilisation d’une boucle for avec range. Puisque range s’arrête un cran avant la valeur passée en paramètres, i ne vaut jamais n. Le facteur n est compté une seule fois, à l’initialisation de s.
  • l’utilisation de la division entière, sans quoi la fonction renverrait 1140.0 et non 1140 dans l’exemple

Le passage des paramètres est équivalent à une affectation, ce qui implique certaines conséquences que nous avons commencé à évoquer dans la toute première section sur les variables et l’affectation. Par exemple, les deux fonction ajoute suivantes ne font pas la même chose :

def ajoute(l, v):
    l.append(v)
    
print(l)
l = [1, 2, 3]
ajoute(l, 42)
print(l)
def ajoute(l, v):
    l = l + [v]
    
print(l)
l = [1, 2, 3]
ajoute(l, 42)
print(l)

Nous laissons le lecteur méditer cet exemple.

Pour plus d’informations sur le passage des paramètres, on pourra consulter :

  • le document Affection, mode de passage des paramètres, [ALGOPROG-AFF] (voir documentation

Listes en compréhension #

Les listes en compréhension ne sont pas un passage incontournable, mais si agréable et spécifique à Python qu’il est difficile de ne pas en parler ici.

La notation est tellement naturelle et claire que des exemples suffisent à en montrer le principe :

>>> [i for i in range(20)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> [i ** 2 for i in range(20)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]
>>> [i ** 2 for i in range(20) if i % 3 == 0]
[0, 9, 36, 81, 144, 225, 324]

Autres constructions intéressantes #

Python possède beaucoup d’autres élément intéressant, qu’il n’est pas nécessaire de connaître pour commencer, mais qui sont très pratiques/puissants :

  • les générateurs
  • les exceptions
  • la programmation orientée objets
  • les décorateurs

Avant de passer à la seconde partie de ce livret, nous vous invitons à jeter in coup d’œil rapide à la syntaxe Blockly.

Éléménts de syntaxe Blockly #

Plutôt que de détailler les éléments de syntaxe un par un, voici quelques exemples :

Calcul de Factorielle #

Factorielle

Diviseurs d’un entier


  1. On devrait probablement dire en français les n-uplets, mais en ce qui concerne Python, les ouvrages français préfèrent tuple ↩︎