Aller au contenu

Les essentiels de la programmation en Python

Types et expressions

Au Programme

En Python et dans la plupart des langages de programmation, les valeurs sont typées. Le type d'une valeur définit ce que la valeur réprésente, et les opérations que l'on peut faire dessus.

Par exemple, additionner deux entiers a du sens, mais ajouter un entier et un texte n'a pas de sens.

Les types permettent de faire des vérifications automatiques, et donc de détecter des erreurs d'inatention.

On a pour le moment vu 4 types

  • Les entiers, int, qui correspondent aux nombres entiers relatifs
  • Les flottants, float, qui correspondent aux nombres réels
  • Les booléens, bool, qui peuvent prendre uniquement deux valeurs, True et False.
  • Les chaînes de caractères, str, qui correspondent à du texte.

Les types supportent des opérations sous forme d'opérateurs. Voir le cours pour les opérateurs supportés par chaque type. Voici les principaux :

opérateur types opération
+ int, float addition
+ str concaténation (mise bout à bout)
- int, float soustraction
* int, float multiplication
/ int, float division, resultat type float
// int, int division entière
and bool ET logique
or bool OU logique
not bool NON logique

Combiner les valeur avec des opérateurs donne des expressions. Une expression est évaluée à l'execution pour connaître sa valeur.

Exemple d'expression :

20 - 4 + 3

On peut utiliser des variables dans une expression, la variable sera alors remplacée par sa valeur au moment de l'évaluation. En général, partout où on utilise des valeurs, on peut utiliser des expressions.

a = 20 - 4

L'ordre d'évaluation des opérations d'une expression s'effectue dans un ordre précis. L'ordre est d'une manière générale similaire à l'ordre que l'on retrouve en mathématique, c'est à dire d'abord l'addition et la division, puis l'addition et la soustraction.

Structures de contrôle

Au Programme

séquence : si on écrit des instructions les unes en dessous des autres, elles sont executées dans l'ordre descendant.

if : on peut utiliser un if pour exécuter des instruction seulement si une condition est vérifiée. La condtion est représentée par une valeur booléenne. True si condition vérifiée, False sinon.

if condition:
    #instructions si condition vérifiée

Ajouter un else après un if permet d'executer des instructions seulement si la condition n'est pas vérifiée.

if condition:
    #instructions si condition vérifiée
else:
    #instructions si condition non vérifiée

Si on veut executer des instructions si la condition d'un if n'est pas vérifiée, et si une autre condition est vérifiée, on peut utiliser un elif.

if condition1:
    #instructions si condition 1 vérifiée
elif condition2:
    #instructions si condition 1 non vérifiée et condition 2 vérifiée.

On peut ajouter plusieurs elif à la suite, et aussi un else à la fin.

if condition1:
    #instructions si condition 1 vérifiée
elif condition2:
    #instructions si condition 1 non vérifiée et condition 2 vérifiée
elif condition3:
    #instructions si conditions 1 et 2 non vérifiées et condition 3 vérifiée
else:
    #instructions si conditions 1 à 3 non vérifiées

On peut répéter des instructions tant qu'une condition est vraie en utilisant un while :

while condition:
    #instructions tant que la condition est vraie

Fonctions

Au programme

Une fonction se déclare et se définit avec le mot clé def et la syntaxe suivante :

def nom_fonction(arg1, arg2):
    #ici des instructions
    return ar11 + arg2 #pas obligatoire

arg1 et arg2 sont les arguments ou paramètres de la fonction. Une fonction peut avoir zéro, un ou plusieurs arguments, séparés par des virgules.

On appelle une fonction avec la syntaxe suivante :

nom_fonction(val1, val2)

val1 et val2 sont des valeurs.

l'instruction return permet à la fonction de retourner une valeur, qu'on peut alors utiliser dans une expression.

a = nom_fonction(1,2) + 3

Une fonction peut appeler une autre fonction :

def fonction1():
    pass

def fonction2():
    fonction1()

Si on veut appeler une fonction, il faut qu'elle ait été définie plus haut dans le code.

Quand on appelle une fonction, c'est l'ordre des arguments qui importe, pas leurs noms.

def fonction(a,b,c):
    return (a + b) * c

a = 1
b = 100 
c = 1

r = fonction(a, c, b) #r vaut (1 + 1) *100

Au Programme

On spécifie ou prototype une fonction en écrivant une docstring qui décrit des contraintes de type ou de valeur sur ses arguments (la précondition), la valeur qu'elle retourne et ce qu'elle fait (postcondition) et d'éventuels exemples. On utilise éventuellement des assertions pour vérifier tout ou une partie de la précondition, avec l'instruction assert condition.

def division(a, b):
    """a, b des entiers, b != 0
    retourne a/b

    exemple :
    division(6,2) vaut 3
    ```
    assert(type(a) == int and type(b) == int)
    assert(b != 0)
    return a / b

Les variables dans le corps d'une fonction et les arguments d'une fonction sont locales à la fonction, et deux variables peuvent avoir le même nom si elles sont dans des fonctions différentes.

Les fonctions facilitent le partage de code entre les programmeurs, à travers des bibliothèques. En Python, on utilise une bibliothèque avec le mot clé import, qui dit à Python de charger la bibliothèque, et avec l'opérateur ., qui permet d'accéder aux éléments dans la bibliothèque:

import random

print(random.randint(1,4)) #affiche un entier aléatoire entre 1 et 4

Pour le cours

On utilise des fonctions pour rendre un programme plus simple à comprendre et à modifier en le divisant en petits morceaux abstraits (ou "cachés") derrière des spécifications.

Types séquences str, tuple, list

Au programme

On peut en Python grouper des données sous forme d'une séquence ayant un ordre défini. Les principaux types séquence sont :

  • str, les chaines de caractères
  • list, les listes, ou tableaux indexés
  • tuple, les n-uplets

Syntaxe de création :

chaine1 = "une chaine"
chaine2 = 'autre chaine'
liste = [10,20,30,40]
nuplet = (10,20,30,40)

On peut accéder à un élément par sa position en utilisant l'opérateur []. Attention, les positions sont comptées à partir de 0.

el0 = chaine1[0] #vaut "u"
el2 = liste[2] #vaut 30
el3 = nuplet[3] #vaut 40

Une boucle for peut être utilisée pour parcourir les éléments d'une séquence :

for e in liste:
    print(e)
#affiche 
#10
#20
#30
#40

On peut stocker des éléments de types différents dans un tuple ou une list. Toutefois, on préfère stocker uniquement des éléments de même type dans des listes pour que le code soit plus simple à lire et à comprendre.

Les tuple et str sont immuables (en anglais immutable): on ne peut pas modifier les valeurs qu'ils contiennent. En revanche, les list ne sont pas immuable (en anglais, mutable). On peut donc modifier des valeurs à l'intérieur d'une list en utilisant

l = [10, 20, 40, 50]
print(l)
l[3] = 0 #on change la valeur du 3eme element de l
print(l)

affiche

[10, 20, 40, 50]
[10, 20, 40, 0]

Pour le cours

On peut ajouter une valeur à une list en utilisant la méthode append

l = [1,2,3]
l.append(5)
print(l)

affiche

[1, 2, 3, 5]

La méthode remove permet de retirer la première occurrence d'une valeur d'une list :

l = [1,2,3,2,5]
l.remove(2)
print(l)

affiche

[1, 3, 2, 5]

On peut concaténer deux listes avec l'opérateur + :

print([1,2,3] + [3,2,1])

affiche

[1, 2, 3, 3, 2, 1]

On peut vérifier si une valeur est présente dans une séquence avec l'opérateur in:

t = (1,2,3,4)
a = 1 in t #a vaut True
b = 5 in t #b vaut False

On peut vérifier si deux séquences de même type contiennent les mêmes valeurs dans le même ordre avec l'opérateur =:

a = [1,2,3] == [2,3,4] #a vaut False
a = [1,2,3] == [1,3,2] #a vaut False
a = [1,2,3] == [1,2,3] #a vaut True
a = [1,2,3] == (1,2,3) #a vaut False (type différents : list et tuple)

Immutabilité et mutabilité

Pour le cours

Certaines valeurs ne sont pas copiées par l'opérateur =, ou quand elles sont passées à une fonction. A la place, elles deviennent liées à plusieurs variables, qui pointent vers elles. Une modification à travers une de ces variables impacte les autres.

C'est le cas des valeurs de type list

On peut modifier directement une valeur de type list, on dit qu'elles sont mutables:

l = [1,2,3,4,5]
l[2] = 0 #change la valeur de l'élément de l en position 2
# ici, l vaut [1,2,0,4,5]
l.append(2) #ajoute la valeur 2 a la fin de l
#ici, l vaut [1,2,0,4,5,2]
l.remove(2) #retire la première occurence de 2 de l
#ici, l vaut [1,0,4,5,2]

Aussi, si on modifie une list dans une fonction, les variables liées à l'extérieur de la fonction seront aussi impactées par les changements. On appelle ça l'effet de bord.

def modifier(l):
    l.append(2)
    print("l dans fonction vaut " + str(l))


a = [1,2,3]
print("a avant fonction vaut " + str(a))
modifier(a)
print("a après fonction vaut " + str(a))

affiche

a avant fonction vaut [1, 2, 3]
l dans fonction vaut [1, 2, 3, 2]
a après fonction vaut [1, 2, 3, 2]

La mutabilité est souvent pratique et bien utilisée, elle permet de gains de performance. En revanche, elle est aussi source d'erreurs. Alors souvent on voudra copier les list explicitement, en utilisant la méthode copy.

def modifier(l):
    lc = l.copy()
    l.append(2)
    print("l dans fonction vaut " + str(l))


a = [1,2,3]
print("a avant fonction vaut " + str(l))
modifier(a)
print("a après fonction vaut " + str(l))

affiche

a avant fonction vaut [1, 2, 3]
l dans fonction vaut [1, 2, 3, 2]
a après fonction vaut [1, 2, 3]

A l'inverse, les valeurs de type tuple ne peuvent être modifiées. On dit que ces valeurs sont immutables. Même si l'immutabilité permet plus de sécurité, elle rends certaines opérations peu intuitives et peu performantes.

A noter que dans le programme, l'immutabilité s'appelle immuabilité. C'est le terme réel français, mais ce cours lui préfère l'anglicisme immutabilité, qui est très fréquent et moins sujet à confusion.