Programmation Python/Version imprimable2a

Ceci est la version imprimable de Programmation Python.
  • Si vous imprimez cette page, choisissez « Aperçu avant impression » dans votre navigateur, ou cliquez sur le lien Version imprimable dans la boîte à outils, vous verrez cette page sans ce message, ni éléments de navigation sur la gauche ou en haut.
  • Cliquez sur Rafraîchir cette page pour obtenir la dernière version du wikilivre.
  • Pour plus d'informations sur les version imprimables, y compris la manière d'obtenir une version PDF, vous pouvez lire l'article Versions imprimables.


Programmation Python

Une version à jour et éditable de ce livre est disponible sur Wikilivres,
une bibliothèque de livres pédagogiques, à l'URL :
https://fr.wikibooks.org/wiki/Programmation_Python

Vous avez la permission de copier, distribuer et/ou modifier ce document selon les termes de la Licence de documentation libre GNU, version 1.2 ou plus récente publiée par la Free Software Foundation ; sans sections inaltérables, sans texte de première page de couverture et sans Texte de dernière page de couverture. Une copie de cette licence est incluse dans l'annexe nommée « Licence de documentation libre GNU ».

Afficher un texte

Ce chapitre détaille les différentes manières d'afficher un texte en console, par exemple pour générer des logs. Les interfaces graphiques plus élaborées seront traitées avec des bibliothèques.

print()

modifier

La fonction print sert à afficher des données sur la sortie standard, qui est l’écran. Exemple :

fonction print
>>> print('Hello World!')
Hello World!

La fonction help de l'interpréteur interactif donne la syntaxe des arguments de la fonction print :

>>> help(print)
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.
modifier

Il est possible de changer une partie du texte en y incorporant des marqueurs de conversion précédés de l'opérateur "%". Il s'agit alors d'un "print formaté" (comme avec printf dans d'autres langages).

Les paramètres placés entre parenthèses à droite de la chaîne à afficher seront insérés dedans, en lieu et place des marqueurs. Cette technique a l'avantage de convertir automatiquement les variables pour qu'elles s'inscrivent dans le texte et qu'elles s'affichent.

Parmi les marqueurs disponibles[1], on trouve :

  • %s représente un paramètre de type "string" (texte).
  • %d un "digit" (nombre entier).
  • %f un "floating" (flottant : nombre réel).

Exemple :

>>> int1, int2 = 1, 2

>>> print(u"le résultat de " + str(int1) + ' + ' + str(int2) + " est " + str(int1 + int2))
  le résultat de 1 + 2 est 3

>>> print(u"le résultat de", int1 , ' + ', int2, " est ", int1 + int2)
  le résultat de 1 + 2 est 3

>>> print(u"et le résultat de %s + %d est %f" % (int1, int2, int1 + int2))
  et le résultat de 1 + 2 est 3.000000

Depuis la 3.6, On peut aussi format de cette manière :

  • f"{variable1} blabla {variable2} etc."

Donc en reprenant l'exemple au-dessus :

>>> int1, int2 = 1, 2

>>> print(f"et le résultat de {int1} + {int2} est {int1 + int2}")
  et le résultat de 1 + 2 est 3

Cela équivaut à utiliser la méthode format :

>>> a, b = 1, 2

>>> # Paramètres nommés
>>> print("et le résultat de {int1} + {int2} est {int1 + int2}".format(int1=a, int2=b))
  et le résultat de 1 + 2 est 3

>>> # Paramètres ordinaux (il n'est pas possible de mettre une expression, il faut passer le résultat)
>>> print("et le résultat de {0} + {1} est {2}".format(int1,int2,int1+int2))
  et le résultat de 1 + 2 est 3

fstring

modifier

Similaire au print formaté, la syntaxe fstring est la suivante :

ma_variable = 1
print(f"Valeur de ma variable : {ma_variable}")

input()

modifier

la fonction input() fait comme la fonction print(), mais stoppe le programme en attente que l'utilisateur presse "entrée". Son résultat sera de type 'string' (chaîne de caractère, texte).

Ici le contenu de ce que l'utilisateur a tapé avant de valider sera stocké dans la variable nommée variable.

>>> variable = input('Quel est votre nom ? ')
Quel est votre nom ? Pierre Henry FAGAN
>>> type(variable)
<class 'str'>
>>> print('Bonjour ' + variable)
Bonjour Pierre Henry FAGAN

raw_input()

modifier

raw_input() fait comme input(), mais renvoie toujours une chaîne de caractère. Elle ne plante pas si le texte est vide.

 

À partir de Python 3.1, la fonction "raw_input()" n'existe plus, et la fonction input() la remplace et renvoie systématiquement une chaîne de caractères.

Afficher des caractères spéciaux

modifier

Normalement, les symboles ne faisant pas partie du code ASCII sont traités comme les autres. Ex :

print('à â ç é è ê ë ï ô ù ÿ')
à â ç é è ê ë ï ô ù ÿ

Toutefois selon l'encodage, il peut être nécessaire de les convertir en Unicode en plaçant un "u" avant :

print(u'à â ç é è ê ë ï ô ù ÿ')

Pour les retours à la ligne, utiliser "\n".

Antislash

modifier

Les caractères affichés par les fonctions précédentes doivent être encadrés par des apostrophes ou des guillemets, mais que se passe-t-il s'ils contiennent eux-mêmes ces symboles ?

Testons la fonction print  :

ce qui marche :
>>> print("ça marche aussi")
ça marche aussi
>>> print('et ça ? "ça marche" ou pas')
et ça ? "ça marche" ou pas
>>> print("et on 'essaye' l'inverse")
et on 'essaye' l'inverse
ce qui ne marche pas :
>>> print('un simple guillemet ' encadré par du simple quote ')
[message d'erreur]
>>> print(" pareil pour le " double ")
[message d'erreur]
>>> print("double " deux " fois dans double")
[message d'erreur]

En Python, le simple quote peut encadrer le double, et le double peut encadrer le simple, car la chaîne commence au premier guillemet et finit au même guillemet.


Pour s'affranchir de ces limitations, on utilise un caractère d'échappement, qui est, en Python, l'antislash (« \ »). Il permet quelques subtilités complémentaires :

  • En premier lieu, il permet d'écrire sur plusieurs lignes n'importe quel type de commande. Pratique pour éviter de dépasser les 120 caractères pouvant nécessiter l'utilisation d'un ascenseur latéral pour être lus.
  • À l'intérieur d'une chaîne de caractères, l’antislash permet d'insérer un certain nombre de codes spéciaux (sauts à la ligne, apostrophes, guillemets, etc.). Exemples :
>>> print('une chaîne avec des \' guillemets \' simples dans des simples, c\'est protégé ')
une chaîne avec des ' guillemets ' simples dans des simples, c'est protégé

>>> txt3 = '"N\'est-ce pas ?" répondit-elle.'
>>> print(txt3)
"N'est-ce pas ?" répondit-elle.

>>> Salut = "Ceci est une chaîne plutôt longue\n contenant plusieurs lignes \
... de texte (Ceci fonctionne\n de la même façon en C/C++.\n\
...     Notez que les blancs en début\n de ligne sont significatifs.\n"
>>> print(Salut)
Ceci est une chaîne plutôt longue
 contenant plusieurs lignes de texte (Ceci fonctionne
 de la même façon en C/C++.
    Notez que les blancs en début
 de ligne sont significatifs.

On remarque que la séquence \' permet d'insérer une apostrophe dans une chaîne délimitée par des apostrophes, et \" par des guillemets. De même, "\\" affiche "\".

D'autres caractères peuvent aussi être introduits par antislash :

  • Retour chariot : \n
  • Tabulation : \t

Triple quotes

modifier

Si le nombre d’antislash nuit à la lisibilité du code, on peut délimiter la chaîne à l'aide de triples guillemets ou de triples apostrophes :

>>> a1 = """
... Usage: trucmuche[OPTIONS]
... { -h
...   -H hôte
... }"""

>>> print(a1)

Usage: trucmuche[OPTIONS]
{ -h
  -H hôte
}

Commentaires

modifier

Tout ce qui suit un dièse (#) jusqu'à un retour à la ligne est un commentaire : ce n'est pas pris en compte par l'interpréteur. Mais cette règle ne s'applique pas lorsque le dièse est positionné dans une chaîne de caractères (entre quotes).

Le but reste de produire du code compréhensible sans commentaire, mais ce texte affiché uniquement dans le code source, peut servir à expliquer à celui qui relit le code (y compris soi-même), les subtilités les moins évidentes de celui-ci.

# Toute cette première ligne est un commentaire.
print("Bonjour le monde") # Ceci est également un commentaire
print("Bonjour"); print("Le monde"); # Ceci est une ligne comportant
# plusieurs instructions
print("Cette ligne ne contient pas de #commentaire")
Exemple 1 : On notera que la fonction print affiche son argument.


Commentaires de bloc

modifier

Les commentaires de bloc (block comments en anglais) permettent de commenter plusieurs lignes. En Python, ils sont assurés par des triples apostrophes ou guillemets :

print('début')
'''
Le paragraphe suivant est commenté
sur plusieurs lignes
'''
print('fin')

Couleurs

modifier

Il est possible d'écrire en couleurs dans un terminal ANSI (Linux) en précisant leurs codes[2]. Exemple :

print('\x1b[31;40m' + ' Texte rouge ' + '\x1b[0m')
print('\x1b[30;42m' + ' Fond vert ' + '\x1b[0m')

Références

modifier


Structure d'un programme

Les instructions

modifier

Un programme Python est composé d'instructions. Une instruction est un ordre unitaire donné à un programme. Par exemple afficher Bonjour est une instruction, de même que calculer un plus un.

La structure d'un programme Python est certainement ce qui étonne le plus le programmeur ayant l'habitude d'un langage plus traditionnel comme le C : en Python les limites des instructions et des blocs sont définies par la mise en page.

  • Le point-virgule (;) à la fin de chaque instruction est remplacé par le caractère de fin de ligne (symbolisé par "\n"). Ce qui simplifie la syntaxe car traditionnellement les points-virgules étaient toujours suivis de retours à la ligne.
  • Les accolades ({}) fréquemment utilisées pour définir les blocs sont remplacées par les niveaux d'indentations. En effet, il était déjà conseillé aux programmeurs de se servir aussi des sauts à la ligne et de l'indentation pour bien délimiter visuellement les blocs, donc c'est également un allègement du code.

En définitive, Python oblige à écrire du code lisible, et à prendre de bonnes habitudes conservables dans d'autres langages, ce qui en fait un langage idéal pour apprendre la programmation.

Les espaces sont ignorés

modifier

À part ceux qui servent à l'indentation, en début de ligne, les espaces placés à l'intérieur des instructions sont ignorés, sauf s'ils font partie d'une chaîne de caractères.

L'interpréteur Python commence par analyser la première ligne :

  • si celle-ci contient une instruction, alors il l'exécute
  • si l'instruction n'est pas une instruction de contrôle, alors, il passe à la ligne suivante, l'analyse et l'exécute
  • si le programme Python arrive à la fin du fichier à exécuter, alors, il sort du programme et en arrête l'exécution.
print("Bonjour")
1+1
c = 3e5
e = m*c**2
a, b, c = 1, 2, 3
discriminant = b**2-4*a*c
lambda x,y : x + y
dico1 = {'prénom':'Eric', 'nom':'tartempion'}
print ("Bonjour %s" % dico1['nom'])
Exemple 1 : quelques instructions


Notion de bloc d'instructions

modifier
 
Notez que le code du bloc le plus externe (bloc 1) ne peut pas lui-même être écarté de la marge de gauche (il n'est imbriqué dans rien).

Un bloc d'instructions est une suite d'instructions qui est alignée sur la même tabulation. Les blocs d'instructions sont créés par les instructions de contrôles comme if, while et for, ainsi que par les instructions permettant de déclarer des fonctions.

Sous Python, toutes les instructions composées ont toujours la même structure : une ligne d'en-tête terminée par un double point, suivie d'une ou de plusieurs instructions indentées sous cette ligne d'en-tête.

Ligne d'en-tête:
    première instruction du bloc
    ... ...
    ... ...
    dernière instruction du bloc

Il y a deux solutions pour indenter : utiliser quatre espaces ou un seul caractère tabulation, mais jamais un mélange des deux sous peine d'erreurs IndentationError: unindent does not match any outer indentation level. En effet, et même si le résultat paraît identique à l'écran, espaces et tabulations sont des codes binaires distincts : Python considérera donc que ces lignes indentées différemment font partie de blocs différents.

La tabulation est notamment la convention utilisée pour la librairie standard de Python, mais les espaces ont l'avantage de fonctionner avec tous les éditeurs (et ainsi, de pouvoir être plusieurs sur le même projet avec des éditeurs différents). On préférera donc se passer des tabulations : si vous utilisez un éditeur "intelligent", vous pouvez escamoter le problème en activant l'option "Remplacer les tabulations par des espaces", qui modifie ce que produit la touche tab.

S'il y a plusieurs instructions indentées sous la ligne d'en-tête, elles doivent l'être exactement au même niveau. Ces instructions indentées constituent ce que nous appellerons désormais un bloc d'instructions. Un bloc d'instructions est une suite d'instructions formant un ensemble logique, qui n'est exécuté que dans certaines conditions définies dans la ligne d'en-tête.

#Ce bloc d'instruction est collé contre le bord gauche du fichier
print("Je suis dans le premier bloc")
print("Je suis toujours dans le premier bloc")

if (a == 12) : #L'instruction ''if'' initie un nouveau bloc
    #Ce bloc est a quatre espace du bord
    print("Je suis dans le second bloc")
    print("Je suis encore dans le second bloc")

    if (b == 13 ) :
        #Il est possible d'imbriquer des blocs dans des blocs
        print("Je suis dans un troisième bloc")
        print("et ici aussi")

    print("Je reviens dans le second bloc")

print("Je suis revenu(e) dans le premier bloc")
Exemple 2 : Les blocs


Variables

Affectations

modifier
Début d’un principe
Fin du principe


En Python comme dans de nombreux autres langages, le symbole = est l'opérateur d'affectation. Cette valeur restera accessible jusqu'à la fin de l'exécution du programme (vérifiable avec "print(x)").

La valeur de la variable peut être un littéral, c'est-à-dire une constante, ou bien une expression (ex : une autre variable ou une instruction comme "1+1"). L'expression est évaluée avant d'être affectée à la variable.

 

En Python les constantes sont déclarées et affectées comme les variables. La convention PEP8 leur impose juste un nom en majuscules[1].

Ex :

BASE_URL = "https://api.example.com"

Réaffectation

modifier

Si la variable affectée n'existe pas, l'ordinateur la crée, sinon il écrase sa valeur. En effet, il est permis de ré-affecter une nouvelle valeur à une même variable, autant de fois qu'on le souhaite.

>>> altitude = 320
>>> print(altitude)
320
>>> altitude = 375
>>> print(altitude)
375

Ceci nous amène à attirer votre attention sur le fait que le symbole égale utilisé sous Python pour réaliser une affectation ne doit en aucun cas être confondu avec un symbole d'égalité tel qu'il est compris en mathématique. Il est tentant d'interpréter l'instruction altitude = 320 comme une affirmation d'égalité, mais ce n'en est pas une !

  • Premièrement, l'égalité est commutative, alors que l'affectation ne l'est pas. Ainsi, en mathématique, les écritures a = 7 et 7 = a sont équivalentes, alors qu'une instruction de programmation telle que 375 = altitude serait illégale.
  • Deuxièmement, l'égalité est permanente, alors que l'affectation peut être remplacée comme nous venons de le voir. Lorsqu'en mathématique, nous affirmons une égalité telle que a = b au début d'un raisonnement, alors a continue à être égal à b durant tout le développement qui suit.

En programmation, une première instruction d'affectation peut rendre égales les valeurs de deux variables, et une instruction ultérieure en changer ensuite l'une ou l'autre. Exemple :

>>> a = 5
>>> b = a  # a et b contiennent des valeurs égales
>>> b = 2  # a et b sont maintenant différentes

Affectations multiples

modifier

Sous Python, on peut assigner une valeur à plusieurs variables simultanément. Exemple d'affectation multiple :

>>> x = y = 7
>>> x
7
>>> y
7

Affectations parallèles

modifier

On peut aussi effectuer des affectations parallèles à l'aide d'un seul opérateur :

>>> a, b = 4, 8.33
>>> a
4
>>> b
8.33
 Les francophones ont pour habitude d'utiliser la virgule comme séparateur décimal, alors que les langages de programmation utilisent toujours la convention en vigueur dans les pays de langue anglaise, c'est-à-dire le point décimal. La virgule, quant à elle, est très généralement utilisée pour séparer différents éléments (arguments, etc.) comme on le voit dans notre exemple, pour les variables elles-mêmes ainsi que pour les valeurs qu'on leur attribue.

Exercices


  1. Décrivez-le plus clairement et le plus complètement possible ce qui se passe à chacune des trois lignes de l'exemple ci-dessous :
    >>> largeur = 20
    >>> hauteur = 5 * 9.3
    >>> largeur * hauteur
    930.0
    
  2. Assignez les valeurs respectives 3, 5, 7 à trois variables a, b, c. Effectuez l'opération a - b/c . Le résultat est-il mathématiquement correct ? Si ce n'est pas le cas, comment devez-vous procéder pour qu'il le soit ?

Solution1.

>>> largeur = 20 # affecte la valeur 20 à largeur
>>> hauteur = 5 * 9.3 # affecte le résultat à hauteur
>>> largeur * hauteur # multiplie les 2 variables (largeur et hauteur)
930.0 # affiche le résultat de la multiplication des 2 variables

2.

>> a, b, c = 3, 5, 7
>>> a - b/c
2.2857142857142856
>> a - b//c     # // : permet d'avoir un entier tronqué soit la b//c = 0
3

Ou plus avancé avec un import afin de l'avoir sous forme de fraction :

>> from fractions import * # Import du module fraction dans son ensemble
>>> a, b, c = 3, 5, 7
>>> print(a - Fraction(b/c)) # Appel de Fraction du module fractions
20587884010836553/9007199254740992

Principe de fonctionnement

modifier

L'essentiel du travail effectué par un programme d'ordinateur consiste à manipuler des données. Ces données peuvent être très diverses (tout ce qui est numérisable, en fait), mais dans la mémoire de l'ordinateur elles se ramènent toujours en définitive à une suite finie de nombres binaires.

Pour pouvoir accéder aux données, le programme d'ordinateur (quel que soit le langage dans lequel il est écrit) fait abondamment usage d'un grand nombre de variables de différents types.

Une variable apparaît dans un langage de programmation sous un nom de variable à peu près quelconque, mais pour l'ordinateur il s'agit d'une référence désignant une adresse mémoire, c'est-à-dire un emplacement précis dans la mémoire vive.

À cet emplacement est stocké une valeur bien déterminée. C'est la donnée proprement dite, qui est donc stockée sous la forme d'une suite de nombres binaires, mais qui n'est pas nécessairement un nombre aux yeux du langage de programmation utilisé. Cela peut être en fait à peu près n'importe quel « objet » susceptible d'être placé dans la mémoire d'un ordinateur, par exemple : un nombre entier, un nombre réel, un nombre complexe, un vecteur, une chaîne de caractères typographique, un tableau, une fonction, etc.

Exemple

modifier

Prenons l'exemple suivant :

>>> n = 7                       # donner à "n" la valeur "7"
>>> message = "Quoi de neuf ?"  # affecter la valeur "Quoi de neuf ?" à "message"
>>> pi = 3.14159                # assigner sa valeur à la variable "pi"

Les exemples ci-dessus illustrent des instructions d'affectation Python tout à fait classiques. Après qu'on les ait exécutées, il existe dans la mémoire de l'ordinateur, à des endroits différents :

  • trois noms de variables, à savoir "n", "message" et "pi" ;
  • trois séquences d'octets, où sont encodées le nombre entier "7", la chaîne de caractères "Quoi de neuf ?" et le nombre réel "3,14159".

Les trois instructions d'affectation ci-dessus ont eu pour effet chacune de réaliser plusieurs opérations dans la mémoire de l'ordinateur :

  • créer et mémoriser un nom de variable ;
  • lui attribuer un type bien déterminé ;
  • créer et mémoriser une valeur particulière ;
  • établir un lien (par un système interne de pointeurs) entre le nom de la variable et l'emplacement mémoire de la valeur correspondante.

On peut mieux se représenter tout cela par un diagramme d'état tel que celui-ci :

n message pi
7 Quoi de neuf ? 3.14159

Les trois noms de variables sont des références, mémorisées dans une zone particulière de la mémoire que l'on appelle espace de noms, alors que les valeurs correspondantes sont situées ailleurs, dans des emplacements parfois fort éloignés les uns des autres.

Les références

modifier

Formellement, les variables Python sont des références, c'est à dire que écrire "a = ((1,0,0),(0,1,0),(0,0,1))" ne signifie pas que "a" vaut "((1,0,0),(0,1,0),(0,0,1))" mais que "a" référence le n-uplet "((1,0,0),(0,1,0),(0,0,1))". La différence est que ensuite, une autre variable peut référencer le même n-uplet, simplement avec "b = a". Si on modifie "b", alors "a" sera également modifié.

L'utilisation des références
>>> a = [(1,0,0), (0,1,0), (0,0,1)]
>>> b = a
>>> print (a)
[(1,0,0), (0,1,0), (0,0,1)]
>>> print (b)
[(1,0,0), (0,1,0), (0,0,1)]
>>> b[0] = (1,1,0)
>>> print (b)
[(1,1,0), (0,1,0), (0,0,1)]
>>> print (a)
[(1,1,0), (0,1,0), (0,0,1)]

Notez que a et b ne sont pas "liés", ils référencent simplement le même objet.

Si ensuite on fait référence à un nouvel objet (par l'intermédiaire de l'opérateur d'affectation "="), b référencera toujours l'ancien objet, et une modification de l'un des objets ne modifiera pas l'autre.

Indépendances des variables
>>> a = [1,2,3]
>>> b = a
>>> print (a)
[1,2,3]
>>> print (b)
[1,2,3]
>>> a = [4,5,6]
>>> print (b)
[1,2,3]
>>> print (a)
[4,5,6]
>>> a.append(7)
>>> print (a)
[4,5,6,7]
>>> print (b)
[1,2,3]

Idem pour les nombres :

Références et nombres
>>> a = 5
>>> b = a
>>> print (a)
5
>>> print (b)
5
>>> b += 5
>>> print (b)
10
>>> print (a)
5

Noms des variables

modifier

Les noms de variables sont des noms que vous choisissez vous-même assez librement. Efforcez-vous cependant de bien les choisir : de préférence assez courts, mais aussi explicites que possible, de manière à exprimer clairement ce que la variable est censée contenir. Par exemple, des noms de variables tels que "longitude" et "latitude" conviennent mieux que "x" et "y", car un bon programmeur doit veiller à ce que ses lignes d'instructions soient faciles à lire.

Sous Python, les noms de variables doivent en outre obéir à quelques règles simples :

  • Un nom de variable est une séquence de lettres (a → z , A → Z) et de chiffres (0 → 9), qui doit toujours commencer par une lettre.
  • La casse est significative (les caractères majuscules et minuscules sont distingués). Donc "Joseph", "joseph", et "JOSEPH" sont des variables différentes.
  • les 29 « mots réservés » du langage sont déjà pris (ex : "print").
  • Seules les lettres du code ASCII sont autorisées. Les lettres accentuées, les cédilles, les espaces, les caractères spéciaux tels que $, #, @, etc. sont interdits, à l'exception du caractère _ (souligné).
 Sous Python 3 les règles de nommage ont été assouplies, car il devient possible d'utiliser n'importe quel lettre Unicode non opérateur dans les noms. Par exemple, français = 1 est autorisé, mais pas f_en_ = 6.55957.

Il faut également noter que les variables dont le nom commence par le caractère _ ont une signification particulière :

  • les noms commençant par un _ ne sont pas exportés lorsqu'ils se trouvent dans un module ;
  • les noms commençant par deux _ et finissant par deux _ sont réservés par le langage lui-même, notamment pour la programmation orientée objet.
Les noms suivants ne peuvent pas être utilisés comme nom de variable
 41toto  # On ne commence pas par un chiffre
 élément # Contient un caractère accentué, qui ne sont pas autorisés sauf depuis Python 3

De plus, il est recommandé d'écrire les noms de variables avec une minuscule, car l'usage veut qu'on le réserve plutôt la majuscule aux noms de classes.

Si le nom d'une variable doit comporter plusieurs mots, il y a deux possibilités d'écrire le nom de la variable :

  • En snake_case (à la C), c'est à dire en séparant les mots par le caractère "_". Exemple : marge_brut.
  • En CamelCase (à la Java), c'est à dire en séparant les mots par un passage en haut de casse (lettre majuscule). Exemple : margeBrut.

Il convient aussi d'éviter autant que possible l'énumération de variables (toto1, toto2, toto3, ...), cela rend le programme parfaitement incompréhensible et sujet à des erreurs.

Il est possible de préfixer le nom de la variable par son type. Par exemple int_margeBrut, str_message_de_bienvenue, mais cela alourdit très fortement le programme. On pourra par exemple s'inspirer de la notation hongroise qui formalise ce mécanisme.

Sinon, d'autres notations existent ou peuvent être imposées en fonction d'un projet, des habitudes d'une entreprise, etc.

Lister les variables

modifier
  • Variables d'environnement :
 print(os.environ)
  • Variables globales :
 print(globals())
  • Variables locales :
 print(locals())


Opérateurs

Définition

modifier

Un opérateur est un symbole (ou un mot réservé) utilisé pour effectuer une opération entre des opérandes.

Une opérande est une variable, un littéral ou bien une expression.

Une expression est une suite valide d'opérateurs et d'opérandes.

Par exemple, dans l'expression :

x = y + 1

Il y a deux opérateurs ( = et +) et trois opérandes (x, y et 1).

Certains opérateurs peuvent avoir des comportements différents en fonction des types d'opérandes sur lesquels ils agissent : on parle alors de surcharge des opérateurs. Exemple :

  • "+" additionne des nombres, mais concatène des chaînes de caractères.
  • "*" multiplie des nombres entre eux, mais duplique des chaînes de caractères.

Il existe différentes catégories d'opérateur :

Présentation des différents opérateurs

modifier

les opérateurs d'affectation

modifier
  • '='
  • Affectation multiple, e.g. x = y = z = 3
  • Affectation parallèle, e.g. x, y = 1 , 0.5
  • Affectation avec opération : la variable est utilisée comme opérande de gauche et utilisée pour stocker le résultat :
a = 5
a *= 2  #  10
a += 1  #  11
a /= 4  #   2.75

Depuis Python 3.8, l'opérateur morse réalise une affectation dans une expression.

les opérateurs logiques

modifier

Les expressions avec un opérateur logique sont évaluées à 0 ou 1 pour chaque bit des opérandes entiers. Pour chaque bit des opérandes X et Y :

  • X | Y : OU logique.
    Si le bit de X ou le bit de Y est évalué à 1, alors le bit résultant sera 1.
    Sinon, le bit résultant sera 0.
  • X ^ Y : OU exclusif logique.
    Si le bit de X est différent du bit de Y, alors le bit résultant sera 1.
    Sinon, le bit résultant sera 0.
  • X & Y : ET logique.
    Si le bit de X et le bit de Y sont tous les deux évalués à 1, alors le bit résultant sera 1.
    Sinon, le bit résultant sera 0.
  • ~ X : NON logique.
    Le bit résultant est la valeur opposée du bit de X.

les opérateurs booléens

modifier

Les expressions avec un opérateur booléen sont évaluées à True ou False.

  • X or Y : OU booléen.
    Si X est évalué à True, alors l'expression est True et Y n'est pas évalué.
    Sinon, l'expression est évaluée à la valeur booléenne de Y.
  • X and Y : ET booléen.
    Si X est évalué à False, alors l'expression est False et Y n'est pas évalué.
    Sinon, l'expression est évaluée à la valeur booléenne de Y.
  • not X : NON booléen.
    Evalué à la valeur booléenne opposée de X.

En fait, ces opérateurs supportent n'importe quel type d'opérandes car ils sont convertis implicitement en valeur booléenne pour l'évaluation :

  • Un entier est converti à False s'il vaut 0, et à True sinon ;
  • Une chaîne de caractère, un tableau ou un dictionnaire est converti à False si elle / s'il est vide, et à True sinon. Il s'agit du même comportement que le précédent sur les entiers en utilisant le résultat de la fonction len() donnant la taille sous la forme d'un entier.
>>> not ''      # Chaîne vide
True
>>> not 'abc'   # Chaîne non vide
False
>>> not 'False' # Chaîne non vide
False
>>> not 'True'  # Chaîne non vide
False

Pour les opérateurs or et and avec des opérandes non-booléens, le comportement est donc le suivant

  • X or Y : Retourne X si X équivaut à True, sinon retourne Y.
  • X and Y : Retourne X si X équivaut à False, sinon retourne Y.
>>> 0 or 1
1
>>> 0 and 1
0

les opérateurs de comparaisons

modifier

Tout comme les opérateurs logiques, les opérateurs de comparaison renvoient une valeur booléenne "True" ou "False". Les opérateurs de comparaisons s'appliquent sur tous les types de base.

  • < strictement inférieur
  • > strictement supérieur
  • <= inférieur ou égal
  • >= supérieur ou égal
  • == égal
  • != différent
  • <> différent, on utilisera de préférence !=
  • X is Y : X et Y représentent le même objet.
  • X is not Y : X et Y ne représentent pas le même objet

Il est possible d'enchaîner les opérateurs : X < Y < Z, dans ce cas, c'est Y qui est pris en compte pour la comparaison avec Z et non pas l'évaluation de (X < Y) comme on pourrait s'y attendre dans d'autres langages.

les opérateurs mathématiques

modifier
symbole opération types exemples
+ Addition entier, réel

chaîne de caractères

6+4 == 10

"a" + "b"== "ab"

- Soustraction entier, réel 6-4 == 2
* Multiplication entier

réel

chaîne de caractères

6*4 == 24

1.2 * 1 == 1.2

3 * "s" == "sss"

** Puissance entier, réel 12**2 == 144
/ Division entier

réel

6/4 == 1 (Python 2) 1.5 (Python 3)

6./4 == 1.5

// Division entière entier, réel 6//4 == 1
% Modulo entier, réel 6%4 == 2

La division entre deux entiers produit un entier en Python 2, et un nombre à virgule flottante en Python 3.

>>> 8/4
2.0
>>> 8//4
2
Comportement de la division entière et du modulo selon le signe des opérandes
>>> 7 // 4
1
>>> -7 // 4
-2
>>> 7 // -4
-2
>>> -7 // -4
1
>>> 7 % 4
3
>>> -7 % 4
1
>>> 7 % -4
-1
>>> -7 % -4
-3


Priorité des opérations

modifier

Lorsqu'il y a plus d'un opérateur dans une expression, l'ordre dans lequel les opérations doivent être effectuées dépend de règles de priorité. Sous Python, les règles de priorité sont les mêmes que celles qui vous ont été enseignées au cours de mathématique. Vous pouvez les mémoriser aisément à l'aide d'un « truc » mnémotechnique, l'acronyme PEMDAS :

  • P pour parenthèses. Ce sont elles qui ont la plus haute priorité. Elles vous permettent donc de « forcer » l'évaluation d'une expression dans l'ordre que vous voulez.
    Ainsi 2*(3-1) = 4, et (1+1)**(5-2) = 8.
  • E pour exposants. Les exposants sont évalués ensuite, avant les autres opérations.
    Ainsi 2**1+1 = 3 (et non 4), et 3*1**10 = 3 (et non 59049 !).
  • M et D pour multiplication et division, qui ont la même priorité. Elles sont évaluées avant l'addition A et la soustraction S, lesquelles sont donc effectuées en dernier lieu.
    Ainsi 2-2*2 renvoie -2 et non 0 !Et 2+4/2 renvoie 4.0 et non 3.0 (Rappelez-vous que / est l'opérateur de la division décimale).
    Si deux opérateurs ont la même priorité, l'évaluation est effectuée de gauche à droite.
    Ainsi dans l'expression 59*100/60, la multiplication est effectuée en premier, et la machine doit donc ensuite effectuer 5900/60, ce qui donne 98.0.
  • A et S pour addition et soustraction.

Dans le tableau ci-dessous :

  • les opérateurs regroupés entre deux lignes épaisses ont la même priorité.
  • le sens d'évaluation indique l'ordre d'évaluation des opérations dans une expression :
    • → pour une évaluation de gauche à droite : a OP1 b OP2 c == (a OP1 b) OP2 c ;
    • ← pour une évaluation de droite à gauche : a OP1 b OP2 c == a OP1 (b OP2 c).
  • le type peut être :
    • « groupe » pour un couple de caractères encadrant une ou plusieurs expressions,
    • « binaire » pour un opérateur situé entre ses deux opérandes,
    • « ternaire » pour un opérateur utilisant trois opérandes,
    • « unaire » pour un opérateur précédant son unique opérande.
Précédence des opérateurs du plus au moins prioritaire[2]
Symbole Type Évaluation Nom
{} Groupe Agencement de dictionnaire
() Groupe Agencement de n-uplet
[] Groupe Agencement de liste
. Binaire Attribut
() Groupe Argument de fonction
[] Groupe Partie (opérateur d'indiçage)
await Unaire Attente de résultat
** Binaire Puissance
~ Unaire inversion de bit
+ Unaire Positif
- Unaire Négatif
* Binaire Multiplier
@ Binaire Multiplication de matrices
/ Binaire Diviser
// Binaire Résultat entier d'une division
% Binaire Modulo
+ Binaire Addition
- Binaire Soustraction
<< Binaire Décalage à gauche
>> Binaire Décalage à droite
& Binaire et logique
^ Binaire ou exclusif
| Binaire ou logique
in Binaire Test d'appartenance
not in Binaire Test de non appartenance
is Binaire Test d'égalité type
is not Binaire Test de non égalité de type
< Binaire inférieur
> Binaire supérieur
<= Binaire inférieur ou égal
>= Binaire supérieur ou égal
== Binaire est égal
!= Binaire est différent
not Unaire non booléen
and Binaire et booléen
or Binaire ou booléen
if ... else ... Ternaire expression conditionnelle
lambda Binaire expression lambda


Opérateurs et expressions

modifier

On manipule les valeurs et les variables qui les référencent, en les combinant avec des opérateurs pour former des expressions. Exemple :

a, b = 7.3, 12
y = 3*a + b/5

Dans cet exemple, nous commençons par affecter aux variables "a" et "b" les valeurs "7,3" et "12". Python assigne automatiquement le type « réel » à la variable "a", et le type « entier » à la variable "b".

La seconde ligne de l'exemple consiste à affecter à une nouvelle variable "y" le résultat d'une expression qui combine les opérateurs "*", "+" et "/" avec les opérandes "a", "b", "3" et "5". Les opérateurs sont les symboles spéciaux utilisés pour représenter des opérations mathématiques simples, telles l'addition ou la multiplication. Les opérandes sont les valeurs combinées à l'aide des opérateurs.

Python évalue chaque expression qu'on lui soumet, aussi compliquée soit-elle, et le résultat de cette évaluation est toujours lui-même une valeur. À cette valeur, il attribue automatiquement un type, lequel dépend de ce qu'il y a dans l'expression. Dans l'exemple ci-dessus, la variable "y" sera du type réel, parce que l'expression évaluée pour déterminer sa valeur contient elle-même au moins un réel.

Les opérateurs Python ne sont pas seulement les quatre opérateurs mathématiques de base. Il faut leur ajouter l'opérateur "**" pour l'exponentiation, ainsi qu'un certain nombre d'opérateurs logiques, des opérateurs agissant sur les chaînes de caractères, des opérateurs effectuant des tests d'identité ou d'appartenance, etc.

Signalons au passage la disponibilité de l'opérateur modulo, représenté par le symbole "%". Cet opérateur fournit le reste de la division entière d'un nombre par un autre. Essayez par exemple :

>>> 10 % 3  # 1
>>> 10 % 5  # 0

Cet opérateur pourra être utile notamment pour tester si un nombre "a" est divisible par un nombre "b". Il suffira en effet de vérifier que "a % b" donne un résultat égal à zéro.

Exercices

  1. Testez les lignes d'instructions suivantes :
  2. >>>  r , pi = 12, 3.14159
    >>>  s = pi * r**2
    >>>  print(s)
    452.38896
    >>>print(type(r), type(pi), type(s))
    <type 'int'>, <type 'float'>, <type 'float'>
    

Solution On constate qu'une variable appartenant à l'ensemble des nombres entiers, multipliée par un nombre décimal, donne un décimal.

Composition

modifier

Jusqu'ici nous avons examiné les différents éléments d'un langage de programmation, à savoir : les variables, les expressions et les instructions, mais sans traiter de la manière dont nous pouvons les combiner les unes avec les autres.

Or l'une des grandes forces d'un langage de programmation de haut niveau est qu'il permet de construire des instructions complexes par assemblage de fragments divers. Ainsi par exemple, si vous savez comment additionner deux nombres et comment afficher une valeur, vous pouvez combiner ces deux instructions en une seule :

>>> print(17 + 3)
20

Cela n'a l'air de rien, mais cette fonctionnalité qui paraît si évidente va vous permettre de programmer des algorithmes complexes de façon claire et concise. Exemple :

>>> h, m, s = 15, 27, 34
>>> print("nombre de secondes écoulées depuis minuit = ", h*3600 + m*60 + s)

Attention :

Il y a une limite à ce que vous pouvez combiner ainsi. Le symbole pour l'égalité en mathématique est '='. Le symbole pour l'égalité en programmation Python est '=='

Ainsi par exemple,

  • En mathématique : a + 1 = b ( '=' est symbole de l'égalité et ici on a une équation). m + 1 = b et a * x = b sont ici des équations mathématiques. Cette forme d’écriture est inutilisable pour modifier une variable en programmation.
  • En programmation (Python et dans d'autres langages) : on peut écrire a = a + 1 ( '=' est l'opérateur d'affectation, symbole d'affectation). On affecte à la variable a, à gauche, un nouveau contenu. Cela signifie ici (en programmation uniquement) que la nouvelle valeur de a ( à gauche du signe d'affectation) va être remplacée par l'ancienne valeur de a ( à droite du signe d'affectation) incrémentée ici de la valeur 1. Avec a = a - 2 on décrémente la variable a de la valeur 2.

Nous aurons l'occasion de revenir bientôt sur ce sujet. Mais auparavant, il nous faut encore aborder un autre concept de grande importance.

Références

modifier


Structures de contrôle

Définition

modifier
Début d’un principe
Fin du principe


Les structures de contrôle sont les groupes d'instructions qui déterminent l'ordre dans lequel les actions sont effectuées. En programmation moderne, il en existe seulement trois :

  1. la séquence (ex : chaînes de caractères, tuples et listes) ;
  2. la sélection ;
  3. la répétition.

Séquence d'instructions

modifier
 Sauf mention explicite, les instructions d'un programme s'exécutent les unes après les autres, dans l'ordre où elles ont été écrites à l'intérieur du script.

Le « chemin » suivi par Python à travers un programme est appelé un flux d'instructions, et les constructions qui le modifient sont appelées des instructions de contrôle de flux.

Python exécute normalement les instructions de la première à la dernière, sauf lorsqu'il rencontre une instruction conditionnelle comme l'instruction "if". Une telle instruction va permettre au programme de suivre différents chemins suivant les circonstances.

Sélection ou exécution conditionnelle

modifier

Si nous voulons pouvoir écrire des applications véritablement utiles, il nous faut des techniques permettant d'aiguiller le déroulement du programme dans différentes directions, en fonction des circonstances rencontrées. Pour ce faire, nous devons disposer d'instructions capables de tester une certaine condition et de modifier le comportement du programme en conséquence.

La plus simple de ces instructions conditionnelles est l'instruction "if", qui permet de tester une condition et de n'exécuter les instructions que si cette condition est vérifiée. Exemple :

a = 11
if a > 10 :
    print("a est plus grand que dix")

En exécutant ce programme, on voit "a est plus grand que dix" apparaître à l'écran. On peut perfectionner le programme pour prendre en compte le cas ou "a" est plus petit que dix :

if a > 10 :
    print("a est plus grand que dix")
else:
    print("a n'est pas plus grand que dix")

On utilise aussi parfois "elif" (contraction de "else if") :

if a > 10 :
    print("a est plus grand que dix")
elif a == 10:
    print("a est égal à dix")
else:
    print("a est plus petit que dix")


 En exécutant un "if" dans l'IDLE, on constate que le prompt principal (>>>) est maintenant remplacé par un prompt secondaire constitué de trois points (du moins sur Linux).
>>> if (a > 10):
...     

L'expression entre parenthèses est ce que nous appellerons désormais une condition. L'instruction "if" permet de tester la validité de cette condition, une expression contenant un opérateur de comparaison. Si la condition est vraie, alors l'instruction que nous avons indentée après le « : » est exécutée. Si la condition est fausse, rien ne se passe. Notez que les parenthèses utilisées ici sont optionnelles sous Python. Nous les avons utilisées pour améliorer la lisibilité. Dans d'autres langages, il se peut qu'elles soient obligatoires.

Comme vous l'aurez certainement déjà compris, l'instruction "else" (« sinon », en anglais) permet de programmer une exécution alternative, dans laquelle le programme doit choisir entre deux possibilités. Mais on peut enchainer autant de conditions que nécessaires en utilisant avant l'instruction "elif" (contraction de « else if »).

Exemple :

>>> a = 7
>>> if (a % 2 == 0):
...     print("a est pair")
...     print("parce que le reste de sa division par 2 est nul")
... else:
...     print("a est impair")
...

Dans cet exemple, les deux lignes d'instructions indentées sous la ligne contenant l'instruction "if" constituent un même bloc logique : ces deux lignes ne sont exécutées - toutes les deux - que si la condition testée avec l'instruction "if" se révèle vraie, c'est-à-dire si le reste de la division de "a" par "2" est nul.

Instructions imbriquées

modifier

Il est parfaitement possible d'imbriquer les unes dans les autres plusieurs instructions composées, de manière à réaliser des structures de décision complexes. Exemple :

if embranchement == "vertébrés":
    if classe == "mammifères":
        if ordre == "carnivores":
            if famille == "félins":
                print ("c'est peut-être un chat")
        print "c'est en tous cas un mammifère"
    elif classe == 'oiseaux':
        print ("c'est peut-être un canari")
print ("la classification des animaux est complexe")

Analysez cet exemple. Ce fragment de programme n'imprime la phrase « c'est peut-être un chat » que dans le cas où les quatre premières conditions testées sont vraies.

Pour que la phrase « c'est en tous cas un mammifère » soit affichée, il faut et il suffit que les deux premières conditions soient vraies. L'instruction d'affichage de cette phrase (ligne 6) se trouve en effet au même niveau d'indentation que l'instruction : if ordre == "carnivores": (ligne 3). Les deux font donc partie d'un même bloc, lequel est entièrement exécuté si les conditions testées aux lignes 1 & 2 sont vraies.

Pour que la phrase « c'est peut-être un canari » soit affichée, il faut que la variable embranchement contienne « vertébrés », et que la variable classe contienne « oiseaux ».

Quant à la phrase de la ligne 9, elle est affichée dans tous les cas, parce qu'elle fait partie du même bloc d'instructions que la ligne 1.

De manière générale, un bloc contient tout le code avec une même indentation.

ceci est le bloc principal
if condition:
    bloc 2
    if condition2:
        bloc 3
    fin du bloc 2
fin du bloc 1

Si à un endroit on a syntaxiquement besoin d'un bloc mais qu'il n'y a rien à faire, on peut utiliser l'instruction pass, qui justement ne fait rien.

if condition:
    pass
else:
    instruction



Instructions répétitives

L'instruction "while"

modifier

Cette instruction est une boucle, c'est-à-dire qu'elle permet de répéter plusieurs fois un bloc d'instructions (en boucle).

"while" exécute des commandes tant qu'une ou plusieurs conditions sont vraies.

while condition:
   commandes

par exemple :

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

donne à l'exécution :

1 2 3 4 5

En effet, la seconde ligne indique à Python qu'il lui faut répéter continuellement le bloc d'instructions qui suit, tant que le contenu de la variable "a" reste inférieur à "5".

Comme l'instruction "if", l'instruction "while" amorce une instruction composée. Le double point à la fin de la ligne introduit le bloc d'instructions à répéter, lequel doit obligatoirement se trouver en retrait.

Nous avons ainsi construit notre première boucle de programmation, laquelle répète un certain nombre de fois le bloc d'instructions indentées. Voici comment cela fonctionne :

  • Avec l'instruction "while", Python commence par évaluer la validité de la condition fournie entre parenthèses (celles-ci sont optionnelles, nous ne les avons utilisées que pour clarifier notre explication).
  • Si la condition se révèle fausse, alors tout le bloc qui suit est ignoré et l'exécution du programme se termine.
  • Si la condition est vraie, alors Python exécute tout le bloc d'instructions constituant le corps de la boucle, c'est-à-dire :
    • l'instruction a = a + 1 qui incrémente d'une unité le contenu de la variable "a" (ce qui signifie que l'on affecte à la variable "a" une nouvelle valeur, qui est égale à la valeur précédente augmentée d'une unité).
    • l'instruction "print" qui affiche la valeur courante de la variable "a".
  • Lorsque ces deux instructions ont été exécutées, nous avons assisté à une première itération, et le programme boucle, c'est-à-dire que l'exécution reprend à la ligne contenant l'instruction "while". La condition qui s'y trouve est à nouveau évaluée, et ainsi de suite.
    Dans notre exemple, si la condition a < 5 est encore vraie, le corps de la boucle est exécuté une nouvelle fois et le bouclage se poursuit.

Remarques

modifier
  • La variable évaluée dans la condition doit exister au préalable (il faut qu'on lui ait déjà affecté au moins une valeur).
  • Si la condition est fausse au départ, le corps de la boucle n'est jamais exécuté.
  • Si la condition reste toujours vraie, alors le corps de la boucle est répété indéfiniment (tout au moins tant que Python lui-même continue à fonctionner), en risquant de saturer les processeurs (si cela survient, presser CTRL + C pour annuler le lancement). Il faut donc veiller à ce que le corps de la boucle contienne au moins une instruction qui change la valeur d'une variable intervenant dans la condition évaluée par "while", de manière à ce que cette condition puisse devenir fausse et donc que la boucle se termine.

Exemple de boucle infinie (à éviter) :

>>> n = 3
>>> while n < 5:
...    print("hello !")

Exemple : élaboration d'une table de multiplication.

>>> a = 0
>>> while a < 12:
...     a = a + 1
...     print(a, a**2 , a**3)
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
11 121 1331
12 144 1728

On obtient donc la liste des carrés et des cubes des nombres de 1 à 12.

Construction d'une suite mathématique

modifier

Le petit programme ci-dessous permet d'afficher les dix premiers termes d'une suite appelée « suite de Fibonacci ». Il s'agit d'une suite de nombres, dont chaque terme est égal à la somme des deux termes qui le précèdent. Analysez ce programme (qui utilise judicieusement l'affectation multiple). Décrivez le mieux possible le rôle de chacune des instructions.

>>> a, b, c = 1, 1, 1
>>> while c < 11 :
...    print b,                 # print ( b , end=" " ) avec python3
...    a, b, c = b, a+b, c+1

Lorsque vous lancez l'exécution de ce programme, vous obtenez :

1 2 3 5 8 13 21 34 55 89

Les termes de la suite de Fibonacci sont affichés sur la même ligne. Vous obtenez ce résultat grâce à la virgule placée à la fin de la ligne qui contient l'instruction "print". Si vous supprimez cette virgule, les nombres seront affichés l'un en-dessous de l'autre.

Lorsque vous examinez un problème de cette nature, vous devez considérer les lignes d'instruction, bien entendu, mais surtout décortiquer les états successifs des différentes variables impliquées dans la boucle. Cela n'est pas toujours facile, loin de là. Pour vous aider à y voir plus clair, prenez la peine de dessiner sur papier une table d'états similaire à celle que nous reproduisons ci-dessous pour notre programme « suite de Fibonacci » :

Variables a b c
Valeurs initiales 1 1 1
Valeurs prises successivement, au cours des itérations 1
2
3
5
2
3
5
8
2
3
4
5
Expression de remplacement b a+b c+1

Dans une telle table, on effectue en quelque sorte « à la main » le travail de l'ordinateur, en indiquant ligne par ligne les valeurs que prendront chacune des variables au fur et à mesure des itérations successives. On commence par inscrire en haut du tableau les noms des variables concernées. Sur la ligne suivante, les valeurs initiales de ces variables (valeurs qu'elles possèdent avant le démarrage de la boucle). Enfin, tout en bas du tableau, les expressions utilisées dans la boucle pour modifier l'état de chaque variable à chaque itération.

On remplit alors quelques lignes correspondant aux premières itérations. Pour établir les valeurs d'une ligne, il suffit d'appliquer à celles de la ligne précédente, l'expression de remplacement qui se trouve en bas de chaque colonne. On vérifie ainsi que l'on obtient bien la suite recherchée. Si ce n'est pas le cas, il faut essayer d'autres expressions de remplacement.

Exercices

  1. Écrivez un programme qui affiche les 20 premiers termes de la table de multiplication par 7.
  2. Écrivez un programme qui affiche une table de conversion de sommes d'argent exprimées en euros, en dollars canadiens. La progression des sommes de la table sera « géométrique », comme dans l'exemple ci-dessous :
    1 euro(s) = 1.65 dollar(s)
    2 euro(s) = 3.30 dollar(s)
    4 euro(s) = 6.60 dollar(s)
    8 euro(s) = 13.20 dollar(s)
    etc. (S'arrêter à 16384 euros)
    
  3. Écrivez un programme qui affiche une suite de 12 nombres dont chaque terme soit égal au triple du terme précédent.

Solution

  1. >>> c = 0
    >>> while c < 20:
    ...     c = c +1
    ...     print c, "x 7 =", c*7
    

    ou encore :

    >>> c = 1
    >>> while c <= 20:
    ...     print c, "x 7 =", c*7
    ...     c = c +1
    
  2. >>> s = 1
    >>> while s <= 16384:
    ...     print s, "euro(s) =", s *1.65, "dollar(s)"
    ...     s = s *2
    
  3. >>> a, c = 1, 1
    >>> while c < 13:
    ...     print a,
    ...     a, c = a *3, c+1
    


Exercices

  1. Ecrivez un programme qui calcule le volume d'un parallélépipède rectangle dont sont fournis au départ la largeur, la hauteur et la profondeur.
  2. Ecrivez un programme qui convertisse un nombre entier de secondes fourni au départ, en un nombre d'années, de mois, de jours, de minutes et de secondes.
    (Utilisez l'opérateur modulo : %).
  3. Ecrivez un programme qui affiche les 20 premiers termes de la table de multiplication par 7, en signalant au passage (à l'aide d'une astérisque) ceux qui sont des multiples de 3.
    Exemple : 7 14 21 * 28 35 42 * 49
  4. Ecrivez un programme qui calcule les 50 premiers termes de la table de multiplication par 13, mais n'affiche que ceux qui sont des multiples de 7.
  5. Ecrivez un programme qui affiche la suite de symboles suivante :
    *
    **
    ***
    ****
    *****
    ******
    *******
    

Solution

  1. Réfléchissez !
  2. # Le nombre de secondes est fourni au départ :
    # (un grand nombre s'impose !)
    nsd = 12345678912
    # Nombre de secondes dans une journée :
    nspj = 3600 * 24
    # Nombre de secondes dans un an (soit 365 jours -
    # on ne tiendra pas compte des années bissextiles) :
    nspa = nspj * 365
    # Nombre de secondes dans un mois (en admettant
    # pour chaque mois une durée identique de 30 jours) :
    nspm = nspj * 30
    # Nombre d'années contenues dans la durée fournie :
    na = nsd / nspa         # division <entière> 
    nsr = nsd % nspa        # n. de sec. restantes
    # Nombre de mois restants :
    nmo = nsr / nspm        # division <entière> 
    nsr = nsr % nspm        # n. de sec. restantes
    # Nombre de jours restants :
    nj = nsr / nspj         # division <entière> 
    nsr = nsr % nspj        # n. de sec. restantes
    # Nombre d'heures restantes :
    nh = nsr / 3600         # division <entière> 
    nsr = nsr % 3600        # n. de sec. restantes
    # Nombre de minutes restantes :
    nmi = nsr /60           # division <entière> 
    nsr = nsr % 60          # n. de sec. restantes
    
    print "Nombre de secondes à convertir :", nsd
    print "Cette durée correspond à", na, "années de 365 jours, plus"
    print nmo, "mois de 30 jours,",
    print nj, "jours,",
    print nh, "heures,",
    print nmi, "minutes et",
    print nsr, "secondes."
    
  3. 
    # affichage des 20 premiers termes de la table par 7,
    # avec signalement des multiples de 3 :
    
    i = 1               # compteur : prendra successivement les valeurs de 1 à 20
    while i < 21:
        # calcul du terme à afficher :
        t = i * 7
        # affichage sans saut à la ligne (utilisation de la virgule) :
        print t,
        # ce terme est-il un multiple de 3 ? (utilisation de l'opérateur modulo) :
        if t % 3 == 0:
            print "*",      # affichage d'une astérisque dans ce cas
        i = i + 1           # incrémentation du compteur dans tous les cas
    
  4. Réfléchissez !
  5. Réfléchissez !

L'instruction "for"

modifier

La boucle "for" permet d'exécuter une itération un certain nombre de fois :

>>> for i in range(5):
...    print(i)
0
1
2
3
4

Pour le "foreach" (répétition pour chaque élément d'un itérable) :

>>> for champ in ['champ1', 'champ2', 'champ3']: 
...    print(champ)
champ1
champ2
champ3

Pour avoir les clés avec les valeurs :

dict = {'key1': 'value1', 'key2': 'value2'}
for key in dict:
...     print(key, '->', dict[key])

Les instructions "break", "continue"

modifier

L'instruction "break" permet d'arrêter une boucle avant sa fin. L'instruction "continue" est similaire, mais au lieu d'interrompre la boucle, elle permet de passer à l'itération suivante.

for i in range(5):
    if i==3:
        break
    print i

affichera

0 1 2

tandis que

for i in range(5):
   if i==3:
        continue
   print i

affichera

0 1 2 4


Types

Typage des variables

modifier
Début d’un principe
Fin du principe


Python est un langage à typage dynamique. Cela signifie que bien que gérant différents types, lorsqu'une variable est affectée, l'interpréteur trouvera automatiquement son type sans que l'utilisateur soit contraint de le préciser. Ceci constitue une particularité intéressante de Python, qui le rattache à une famille particulière de langages où l'on trouve aussi par exemple Lisp, Scheme, et quelques autres.

Par opposition, le typage statique est préférable dans le cas des langages compilés comme C++ et Java, parce qu'il permet d'optimiser l'opération de compilation (dont le résultat est un code binaire « figé »). Dans ces langages, il faut toujours - par des instructions distinctes - d'abord déclarer (définir) le nom et le type des variables, et ensuite seulement leur assigner un contenu, lequel doit bien entendu être compatible avec le type déclaré.

Le typage dynamique quant à lui permet d'écrire plus aisément des constructions logiques de niveau élevé (métaprogrammation, réflexivité), en particulier dans le contexte de la programmation orientée objet (polymorphisme). Il facilite également l'utilisation de structures de données très riches telles que les listes et les dictionnaires.


Types natifs

modifier
Liste des types
int Nombre entier optimisé
long Nombre entier de taille arbitraire
float Nombre à virgule flottante
complex Nombre complexe
str Chaîne de caractère
unicode Chaîne de caractère unicode
tuple Liste de longueur fixe
list Liste de longueur variable
dict dictionnaire
file Fichier
bool Booléen
NoneType Absence de type
NotImplementedType Absence d'implementation
function fonction
module module
Tableau 2 : Liste des types prédéfinis en Python
Tableau des types Python 3.x ayant changé de nom depuis 2.x
nom description équivalent 2.x
int nombre entier de longueur arbitraire long
byte chaîne de caractères ASCII str
str chaîne de caractères Unicode unicode

Détermination d'un type

modifier

La fonction type() permet de connaître le type d'une variable.

>>> a=3
>>> type(a)
<type 'int'>
Exemple 1 : utilisation de la fonction type


Conversion des types

modifier

Il existe plusieurs fonctions qui permettent de forcer le type d'une variable en un autre type.

  • bool() : convertit en booléen : "0", "" et "None" donnent "False" et le reste "True".
  • int() : permet de modifier une variable en entier. Provoque une erreur si cela n'est pas possible.
  • long() : transforme une valeur en long.
  • str() : permet de transformer la plupart des variables d'un autre type en chaînes de caractère.
  • float() : permet la transformation en flottant.
  • repr() : similaire à "str". Voir la partie sur les objets
  • eval() : évalue le contenu de son argument comme si c'était du code Python.
  • split() : sépare une chaine en liste.
  • join() : transforme une liste en chaine, dont le séparateur est en préfixe (" ".join(MaListe)).
  • datetime.strptime('20170727222900', '%Y%m%d%H%M%S') : change une chaine en date.
  • maDate.strftime('%Y%m%d%H%M%S') : change une date en chaine.


Numériques

Il existe deux types pour définir des nombres entiers : le type int et le type long. Il existe également un type pour représenter des nombres à virgule : le type float.

Les nombres entiers de type int

modifier

Les int représentent le type le plus facilement représentable sur une architecture donnée. Par exemple, sur une machine 32-bits, la taille d'un int sera de 32-bit, donc un int permettra de représenter des nombres entre   et  , soit entre -2 147 483 648 et 2 147 483 647.

Un littéral int s'écrit tout simplement avec les chiffres de 0 à 9, précédé éventuellement du symbole -. Il est possible d'écrire ce littéral suivant trois bases :

  • la base décimale : le littéral devra commencer par un chiffre entre 1 et 9
  • la base octale (base 8) : le littéral devra commencer par 0 suivi de chiffres de 0 à 7
  • la base hexadécimale (base 16): le littéral devra commencer par 0x suivi de chiffres de 0 à 9 et de lettres de A à F (en minuscule ou majuscule)
x=1
x=0
x=-33
x=4566
x=2147483647
x=076 #équivalent à x=62
x=0xFF #équivalent à x=255
x=0xa1 #équivalent à x=161
Exemple 2 : Quelques entiers int'


Les nombres entiers de type long

modifier

Un entier long est un entier dont la taille n'est limitée que par la mémoire allouée par l'ordinateur à l'interpréteur Python. C'est à dire qu'un long permet d'écrire des entiers aussi grands que l'on veut.

Il existe deux manières d'utiliser des long :

  • il faut rajouter L ou l à la fin d'un littéral entier pour qu'il soit automatiquement long
  • lorsque le résultat d'une opération dépasse la capacité de stockage d'un int, alors, ce résultat est automatiquement convertit en long
x=1L
x=-45l
x=121212121212121212121212121 #Automatiquement converti en long
x=2147483647+1
Exemple 3 : Quelques entiers long'


Il n'est pas nécessaire d'utiliser le type long de manière systématique : pour les entiers de taille raisonnable, le type int est beaucoup plus optimisé.

Pour convertir un long en int (et inversement), il est possible d'utiliser les fonctions int() et long().

x = int(1L) #x est un int
x = long(1) #x est un long
x = int(12121212121212121) #x est quand même un long
Exemple 4 : Utilisation des fonctions int() et long()


Limite entre « integer » et « long »

modifier
Début d’un principe
Fin du principe


Supposons que nous voulions modifier légèrement notre précédent exercice sur la suite de Fibonacci, de manière à obtenir l'affichage d'un plus grand nombre de termes. À priori, il suffit de modifier la condition de bouclage, dans la deuxième ligne. Avec while c<49:, nous devrions obtenir quarante-huit termes. Modifions donc légèrement l'exercice, de manière à afficher aussi le type de la variable principale :

>>> a, b, c = 1, 1, 1
>>> while c<49:
        print (c, " : ", b, type(b))
        a, b, c = b, a+b, c+1
...
...
...  (affichage des 43 premiers termes)
... 
44  :  1134903170 <type 'int'>
45  :  1836311903 <type 'int'>
46  :  2971215073 <type 'long'>
47  :  4807526976 <type 'long'>
48  :  7778742049 <type 'long'>

Que pouvons-nous constater ?

Si nous n'avions pas utilisé la fonction type(), qui nous permet de vérifier à chaque itération le type de la variable b, nous n'aurions rien remarqué du tout : la suite des nombres de Fibonacci s'affiche sans problème (et nous pourrions encore l'allonger de nombreux termes supplémentaires).

Il semble donc que Python soit capable de traiter des nombres entiers de taille illimitée.

L'exercice que nous venons de réaliser indique cependant qu'il se passe « quelque chose » lorsque ces nombres deviennent très grands. Au début du programme, les variables a, b et c sont définies implicitement comme étant du type integer. C'est ce qui se passe toujours avec Python lorsqu'on affecte une valeur entière à une variable, à condition que cette valeur ne soit pas trop grande. Dans la mémoire de l'ordinateur, ce type de donnée est en effet encodé sous la forme d'un bloc de 4 octets (ou 32 bits). Or la gamme de valeurs décimales qu'il est possible d'encoder sur 4 octets seulement s'étend de -2147483648 à + 2147483647 (Voir cours d'informatique générale).

Les calculs effectués avec ce type de variable sont toujours très rapides, parce que le processeur de l'ordinateur est capable de traiter directement par lui-même de tels nombres entiers à 32 bits. En revanche, lorsqu'il est question de traiter des nombres entiers plus grands, ou encore des nombres réels (nombres « à virgule flottante »), les logiciels que sont les interpréteurs et compilateurs doivent effectuer un gros travail de codage/décodage, afin de ne présenter en définitive au processeur que des opérations binaires sur des nombres entiers de 32 bits au maximum.

Vous savez déjà que le type des variables Python est défini de manière dynamique.

Puisqu'il s'agit du type le plus performant (aussi bien en termes de vitesse de calcul qu'en termes d'occupation de place dans la mémoire), Python utilise le type integer par défaut, chaque fois que cela est possible, c'est-à-dire tant que les valeurs traitées sont des entiers compris entre les limites déjà mentionnées plus haut (environ 2 milliards, en positif ou en négatif).

Lorsque les valeurs traitées sont des nombres entiers se situant au-delà de ces limites, leur encodage dans la mémoire de l'ordinateur devient plus complexe. Les variables auxquelles on affecte de tels nombres sont alors automatiquement définies comme appartenant au type « entier long » (lequel est désigné par long dans la terminologie Python).

Ce type long permet l'encodage de valeurs entières avec une précision quasi infinie : une valeur définie sous cette forme peut en effet posséder un nombre de chiffres significatifs quelconque, ce nombre n'étant limité que par la taille de la mémoire disponible sur l'ordinateur utilisé !

Exemple :

>>> a, b, c = 3, 2, 1
>>> while c < 15:
        print (c, ": ", b)
        a, b, c = b, a*b, c+1
	
1 :  2
2 :  6
3 :  12
4 :  72
5 :  864
6 :  62208
7 :  53747712
8 :  3343537668096
9 :  179707499645975396352
10 :  600858794305667322270155425185792
11 :  107978831564966913814384922944738457859243070439030784
12 :  64880030544660752790736837369104977695001034284228042891827649456186234
582611607420928
13 :  70056698901118320029237641399576216921624545057972697917383692313271754
88362123506443467340026896520469610300883250624900843742470237847552
14 :  45452807645626579985636294048249351205168239870722946151401655655658398
64222761633581512382578246019698020614153674711609417355051422794795300591700
96950422693079038247634055829175296831946224503933501754776033004012758368256
>>> 

Dans l'exemple ci-dessus, la valeur des nombres affichés augmente très rapidement, car chacun d'eux est égal au produit des deux termes précédents.

Au départ, les variables a, b et c sont du type integer, puisqu'on leur affecte des petites valeurs numériques entières : 3, 2 et 1. À partir de la 8e itération, cependant, les variables b et a sont automatiquement converties l'une après l'autre dans le type long : le résultat de la multiplication des termes 6 et 7 est en effet déjà bien supérieur à la limite des 2 milliards évoquée plus haut.

La progression continue avec des nombres de plus en plus gigantesques, mais la vitesse de calcul diminue. Les nombres mémorisés sous le type long occupent une place variable dans la mémoire de l'ordinateur, en fonction de leur taille.

Les nombres à virgule flottante (float)

modifier

Un nombre à virgule flottante est un nombre décimal qu'il est possible de représenter par sa mantisse et son exposant. Par exemple, le nombre 125,789 est représentable par le couple (mantisse = 1,25789, exposant = 2). La mantisse étant toujours comprise entre -10 et 10 exclus.

Les nombres sont traduits par la formule  .

Les limites dépendent de l'architecture de la machine et sont équivalentes au type de donnée double du langage C.

Les littéraux peuvent s'écrire avec les chiffres, le caractère point pour indiquer la séparation entre la partie entière et la partie décimale et la lettre 'e' ou 'E' pour spécifier l'exposant.

x = 1.234
x = 1.0 #Notons qu'un entier peut être un flottant
x = 1. #Même résultat que précédemment
x = 1.234e54 #C'est à dire <math>1.234*10^{54}</math>
x = 1.234E54 #idem
x = -1.454e-2 #La mantisse et l'exposant peuvent être négatifs
Exemple 5 : nombres à virgules


Essayons donc ce type de données dans un nouveau petit programme :

>>> a, b, c = 1., 2., 1	            # => a et b seront du type 'float'
>>> while c <18:
...     a, b, c = b, b*a, c+1
...     print (b)

2.0
4.0
8.0
32.0
256.0
8192.0
2097152.0
17179869184.0
3.6028797019e+16
6.18970019643e+26
2.23007451985e+43
1.38034926936e+70
3.07828173409e+113
4.24910394253e+183
1.30799390526e+297
         Inf
         Inf

Comme vous l'aurez certainement bien compris, nous affichons cette fois encore une série dont les termes augmentent extrêmement vite, chacun d'eux étant égal au produit des deux précédents. Au huitième terme, nous dépassons déjà largement la capacité d'un integer. Au neuvième terme, Python passe automatiquement à la notation scientifique (« e+n » signifie en fait : « fois dix à l'exposant n »). Après le quinzième terme, nous assistons à nouveau à un dépassement de capacité (sans message d'erreur) : les nombres vraiment trop grands sont tout simplement notés « inf » (pour « infini »).

Le type float utilisé dans notre exemple permet de manipuler des nombres (positifs ou négatifs) compris entre 10e-308 et 10e+308 avec une précision de 12 chiffres significatifs. Ces nombres sont encodés d'une manière particulière sur 8 octets (64 bits) dans la mémoire de la machine : une partie du code correspond aux 12 chiffres significatifs, et une autre à l'ordre de grandeur (exposant de 10).

Exercices

  1. Écrivez un programme qui convertisse en radians un angle fourni au départ en degrés, minutes, secondes.
  2. Écrivez un programme qui convertisse en degrés, minutes, secondes un angle fourni au départ en radians.
  3. Écrivez un programme qui convertisse en degrés Celsius une température exprimée au départ en degrés Fahrenheit, ou l'inverse.
    La formule de conversion est :  
  4. Écrivez un programme qui calcule les intérêts accumulés chaque année pendant 20 ans, par capitalisation d'une somme de 100 euros placée en banque au taux fixe de 4,3 %
  5. Une légende de l'Inde ancienne raconte que le jeu d'échecs a été inventé par un vieux sage, que son roi voulut remercier en lui affirmant qu'il lui accorderait n'importe quel cadeau en récompense. Le vieux sage demanda qu'on lui fournisse simplement un peu de riz pour ses vieux jours, et plus précisément un nombre de grains de riz suffisant pour que l'on puisse en déposer 1 seul sur la première case du jeu qu'il venait d'inventer, deux sur la suivante, quatre sur la troisième, et ainsi de suite jusqu'à la 64e case.
    Écrivez un programme Python qui affiche le nombre de grains à déposer sur chacune des 64 cases du jeu. Calculez ce nombre de deux manières :
    • le nombre exact de grains (nombre entier)
    • le nombre de grains en notation scientifique (nombre réel)

Solution

  1. # Conversion degrés -> radians
    # Rappel : un angle de 1 radian est un angle qui correspond à une portion
    # de circonférence de longueur égale à celle du rayon.
    # Puisque la circonférence vaut 2 pi R, un angle de 1 radian correspond
    # à 360° / 2 pi , ou encore à 180° / pi
    
    # Angle fourni au départ en degrés, minutes, secondes :
    deg, min, sec  = 32, 13, 49
    
    # Conversion des secondes en une fraction de minute :
    # (le point décimal force la conversion du résultat en un nombre réel)
    fm = sec/60.
    # Conversion des minutes en une fraction de degré :
    fd = (min + fm)/60
    # Valeur de l'angle en degrés "décimalisés" :
    ang = deg + fd
    # Valeur de pi :
    pi = 3.14159265359
    # Valeur d'un radian en degrés :
    rad = 180 / pi
    # Conversion de l'angle en radians :
    arad = ang / rad
    # Affichage :
    print (deg, "°", min, "'", sec, '" =', arad, "radian(s)")
    
  2. Réfléchissez !
  3. # Conversion °Fahrenheit <-> °Celsius
    
    # A) Température fournie en °C :
    tempC = 25
    # Conversion en °Fahrenheit :
    tempF = tempC * 1.8 + 32
    # Affichage :
    print tempC, "°C =", tempF, "°F"
    
    # B) Température fournie en °F :
    tempF = 25
    # Conversion en °Celsius :
    tempC = (tempF - 32) / 1.8
    # Affichage :
    print (tempF, "°F =", tempC, "°C")
    
  4. Réfléchissez !
  5. >>> a, b = 1, 1				# variante :  a, b = 1., 1
    >>> while b<65:
    ...     print (b, a)
    ...     a,b = a*2, b+1
    ...
    

Les nombres complexes

modifier

Python est un des rares langages à proposer un type de base pour les nombres complexes  . Un nombre complexe est un nombre composé d'une partie réelle et d'une partie imaginaire. On note   une des racines du polynôme  .

Dans certains contextes, (comme la physique), la racine de -1 est notée j. C'est ce qui se fait en Python.

Un littéral complexe s'écrit donc : a + bj, avec a et b des variables de type float. Attention, j doit être précédé d'un nombre car sinon, Python l'interprétera comme étant la variable j. Il ne doit pas y avoir d'espace entre ce nombre et j.

x = 1 + 1j
x = 1.2e3 + 1.5e7j
x = 5j + 4 
x = 1 + x*1j
Exemple 5 : quelques nombres complexes


Booléens

Définition

modifier

Un booléen est un type de données qui ne peut prendre que deux valeurs : vrai ou faux. En Python, les constantes littérales sont notées True et False.

Tous les types de variables peuvent être interprétés de manière booléenne. Par exemple, pour les entiers (int), la valeur "0" correspond à "faux" et les autres valeurs à "vrai". Il en est de même pour tous les autres types : une valeur particulière vaut False et le reste des valeurs True. Le tableau suivant présente les valeurs "faux" pour les principaux type de données.

Exemple d'expressions booléennes

modifier
a = 6
b = 7
c = 42
print(1, a == 6)
print(2, a == 7)
print(3, a == 6 and b == 7)
print(4, a == 7 and b == 7)
print(5, not a == 7 and b == 7)
print(6, a == 7 or b == 7)
print(7, a == 7 or b == 6)
print(8, not (a == 7 and b == 6))
print(9, not a == 7 and b == 6)

Affiche :

1 True
2 False
3 True
4 False
5 True
6 True
7 False
8 True
9 False

Que se passe-t-il ? Le programme consiste en un tas de print. Chaque print affiche un nombre et une expression. Le nombre sert à savoir de quel ligne on parle. Notez bien comme chaque expression finit soit par False ou True. En python False et True peuvent aussi être écrits 0 et 1.

Voyez ce code :

print(1, a == 6)
print(2, a == 7)

Cela affiche respectivement a True et a False comme attendu, le premier est vrai, et le second est faux. La troisième ligne, print(3, a == 6 and b == 7), est un peu différente. L'opérateur and signifie que si les deux expressions qui l'entourent sont vraies alors toute l'expression l'est également, autrement elle est fausse. Le comportement de and peut être résumé comme suit :

Expression Résultat
True and True True
True and False False
False and True False
False and False False

Notez que si la première expression est fausse Python ne vérifie pas la seconde car il sait que l'expression car il sait que tout l'expression est fausse. Essayez de lancer False and print("Salut") et comparez le à True and print("Salut"). Le terme technique pour ceci est short-circuit evaluation (littéralement "évaluation en circuit court").

La ligne suivante, print(5, not a == 7 and b == 7), utilise l'opérateur not. not retourne l'opposé d'une expression (l'expression pourrait être réécrite print(5, a != 7 and b == 7)). Voici la table de vérité :

Expression Résultat
not True False
not False True

Les deux lignes suivantes, print(7, a == 7 or b == 7) et print(7, a == 7 or b == 6) utilisent l'opérateur or. or retourne vrai si la première expression est vraie ou si la seconde expression est vraie, si la seconde expression est vraie ou si les deux le sont. Si aucune n'est vraie il retourne faux. Voici sa table de vérité :

Expression Résultat
True or True True
True or False True
False or True True
False or False False

Notez que si la première expression est vraie Python ne vérifie pas la seconde expression car il sait que toute l'expression est vraie. Cela marche car or est vrai si au moins une des expressions est vraie. La première partie est vraie donc la seconde pourrait être vraie ou fausse, mais l'expression est toujours vraie.

Les deux lignes suivantes, print(8, not (a == 7 and b == 6)) et print(9, not a == 7 and b == 6, montrent que les parenthèses peuvent être utilisées pour regrouper des expressions et forcer l’évaluation d'une partie en premier. Notez que les parenthèses ont changé l'expression de "faux" à "vrai". La raison est que les parenthèses ont forcé le not à s'appliquer à toute l'expression au lieu de seulement la partie a == 7.

La valeur booléenne d'une variable "x" peut être obtenue avec bool(x). Voici la table de vérité selon le type de la variable :

Vrai Faux
True False
1 0
Nombre (positif ou négatif) None
Chaine non vide Chaine vide
Liste non vide Liste vide
Dictionnaire non vide Dictionnaire vide

Pour tester si une variable "x" n'est pas nulle, on utilise : not x is None.

Note sur les opérateurs booléens

modifier

 

x == ('a' or 'b') n'est pas équivalent à x == 'a' or x == 'b'. En effet, cela ne vérifie pas si x est équivalent aux caractères 'a' ou 'b', car l'expression booléenne s'arrête avant la fin par short-circuit evaluation.

Exemple :

 >>> 'a' == ('a' or 'b')  # 'a' = True, donc ('a' or 'b') = 'a' sans avoir à évaluer 'b'. Ce qui revient à : 'a' == 'a'
 True

 >>> 'b' == ('a' or 'b')  # Revient à : 'b' == 'a', de la même manière
 False 

 >>> 'a' == ('a' and 'b') # 'a' = True et 'b' = True, donc ('a' and 'b') = 'b' (dernière expression évaluée). Ce qui revient à : 'a' == 'b'
 False

 >>> 'b' == ('a' and 'b') # Revient à : 'b' == 'b', de la même manière
 True

Véracité/fausseté d'une expression

modifier

Lorsqu'un programme contient des instructions telles que while ou if, l'ordinateur qui exécute ce programme doit évaluer la véracité d'une condition, c'est-à-dire déterminer si une expression est vraie ou fausse. Par exemple, une boucle initiée par while c<20: s'exécutera aussi longtemps que la condition c<20 restera vraie.

Mais comment un ordinateur peut-il déterminer si quelque chose est vrai ou faux ?

En fait - et vous le savez déjà - un ordinateur ne manipule strictement que des nombres. Tout ce qu'un ordinateur doit traiter doit d'abord toujours être converti en valeur numérique. Cela s'applique aussi à la notion de vrai/faux. En Python, tout comme en C, en Basic et en de nombreux autres langages de programmation, on considère que toute valeur numérique autre que zéro est « vraie ». Seule la valeur zéro est « fausse ». Exemple :

a = input('Entrez une valeur quelconque')
if a:
    print("vrai")
else:
    print("faux")

Le petit script ci-dessus n'affiche « faux » que si vous entrez la valeur 0. Pour toute autre valeur numérique, vous obtiendrez « vrai ».

Si vous entrez une chaîne de caractères ou une liste, vous obtiendrez encore « vrai ». Seules les chaînes ou les listes vides seront considérées comme « fausses ».

Tout ce qui précède signifie donc qu'une expression à évaluer, telle par exemple la condition a > 5 , est d'abord convertie par l'ordinateur en une valeur numérique. (Généralement 1 si l'expression est vraie, et zéro si l'expression est fausse). Exemple :

a = input('entrez une valeur numérique : ')
b = (a < 5)
print ('la valeur de b est', b, ':')
if b:
    print("la condition b est vraie")
else:
    print("la condition b est fausse")

Le script ci-dessus vous renvoie une valeur b = 1 (condition vraie) si vous avez entré un nombre plus petit que 5.

Ces explications ne sont qu'une première information à propos d'un système de représentation des opérations logiques de l’algèbre de Boole.

Exemple

modifier

Créer le fichier password1.py :

#!/usr/bin/python
# -*- coding:Utf-8 -*-
# Ce programme demande à l'utilisateur son nom et son mot de passe, puis il les vérifie

name = input("What is your name? ")
password = input("What is the password? ")
if name == "Josh" and password == "Friday":
    print("Welcome Josh")
elif name == "Fred" and password == "Rock":
    print("Welcome Fred")
else:
    print("I don't know you.")

Resultats :

 What is your name? Josh
 What is the password? Friday
 Welcome Josh

 What is your name? Bill
 What is the password? Money
 I don't know you.

Exercices

Écrire un programme devine votre nom, avec seulement trois chances avant de terminer.


Solution

#!/usr/bin/python
# coding:Utf-8 

print("Try to guess my name!")
count = 1
name = "guilherme"
guess = input("What is my name? ")
while count < 3 and guess.lower() != name:    # .lower permet ici d'ignorer les majuscules dans le nom
    print("You are wrong!")
    guess = input("What is my name?")
    count = count + 1

if guess.lower() != name:
    print("You are wrong!")
    print("You ran out of chances.")
else:
    print("Yes! My name is", name + "!")


Chaines de caractères

Les données alphanumériques

modifier
Début d’un principe
Fin du principe


À la différence des données numériques, qui sont des entités singulières, les chaînes de caractères (ou string) constituent un type de donnée composite. Nous entendons par là une entité bien définie qui est faite elle-même d'un ensemble d'entités plus petites, en l'occurrence : les caractères. Suivant les circonstances, nous serons amenés à traiter une telle donnée composite, tantôt comme un seul objet, tantôt comme une suite ordonnée d'éléments. Dans ce dernier cas, nous souhaiterons probablement pouvoir accéder à chacun de ces éléments à titre individuel.

En fait, les chaînes de caractères font partie d'une catégorie d'objets Python que l'on appelle des séquences, et dont font partie aussi les listes et les tuples.

Le type « string »

modifier

Sous Python, une donnée de type string est une suite quelconque de caractères délimitée soit par des apostrophes (simple quotes), soit par des guillemets (double quotes), soit par des triples quotes (''' ou """).

Exemples :

>>> phrase1 = 'les œufs durs.'
>>> phrase2 = '"Oui", répondit-il,'
>>> phrase3 = "j'aime bien"
>>> print(phrase2, phrase3, phrase1)
"Oui", répondit-il, j'aime bien les œufs durs.

print("""1, " 2", \n 3,
4""")

Résultat :

1, " 2", 
 3,
4

Les trois variables phrase1, phrase2, phrase3 sont donc des variables de type string.

Accès aux caractères individuels d'une chaîne

modifier

Les chaînes de caractères constituent un cas particulier d'un type de données plus général que l'on appelle des données composites. Une donnée composite est une entité qui rassemble dans une seule structure un ensemble d'entités plus simples : dans le cas d'une chaîne de caractères, par exemple, ces entités plus simples sont évidemment les caractères eux-mêmes. En fonction des circonstances, nous souhaiterons traiter la chaîne de caractères, tantôt comme un seul objet, tantôt comme une collection de caractères distincts. Un langage de programmation tel que Python doit donc être pourvu de mécanismes qui permettent d'accéder séparément à chacun des caractères d'une chaîne.

Python considère qu'une chaîne de caractères est un objet de la catégorie des séquences, lesquelles sont des collections ordonnées d'éléments. Cela signifie simplement que les caractères d'une chaîne sont toujours disposés dans un certain ordre. Par conséquent, chaque caractère de la chaîne peut être désigné par sa place dans la séquence, à l'aide d'un index.

Pour accéder à un caractère bien déterminé, on utilise le nom de la variable qui contient la chaîne, et on lui accole entre deux crochets l'index numérique qui correspond à la position du caractère dans la chaîne.

 Comme vous aurez l'occasion de le vérifier par ailleurs, les données informatiques sont presque toujours numérotées à partir de zéro (et non à partir de un). C'est le cas pour les caractères d'une chaîne.

Exemple :

>>> chaine = "Stéphanie"
>>> print(chaine[0], chaine[3])
S p


Taille des chaines

modifier
  • Déterminer la longueur (c'est-à-dire le nombre de caractères) d'une chaîne, en faisant appel à la fonction intégrée len() :
>>> print(len(c))
29 #La chaîne de caractères 'c' contient 29 caractères !

>>> print(len('Zowerz'))
6

Sous-chaines

modifier

L'opérateur d'indiçage ([]) permet aussi de sélectionner des sous-chaines selon leurs indices. On appelle cette technique le slicing (« découpage en tranches »).

Dans la tranche [n,m], le nième caractère est inclus, mais pas le mième. Si vous voulez mémoriser aisément ce mécanisme, il faut vous représenter que les indices pointent des emplacements situés entre les caractères, comme dans le schéma ci-dessous :

 
illustration du système de numérotation des caractères

Au vu de ce schéma, il n'est pas difficile de comprendre que ch[3:7] extraira iett. Notez qu'il faut impérativement utiliser un deux-points (:) : l'utilisation d'une virgule ou d'un point-virgule retournera une erreur.

De plus, si la borne de départ est le premier caractère (indice 0) ou si celle d'arrivée est la dernière (indice égal à la longueur de la chaine), il devient facultatif. Une borne négative -x prendra le x-ième caractère en partant de la fin, ainsi -1 désignera le dernier caractère, -2 l'avant-dernier, -3 l’antépénultième, etc. Cela ne marche pas avec [-0], qui retournera le premier caractère car -0 = +0. Exemple :

>>> chain = "123456789"
>>> print(chain[1:3])
23

>>> print(chain[0:-1])
12345678
>>> print(chain[:-1])
12345678

>>> print(chain[1:len(chain)])
23456789
>>> print(chain[1:])
23456789

Pour une chaîne de caractère chaine, les indices doivent être compris entre -len(chaine) et +len(chaine)-1. En dehors de cet intervalle, l'interpréteur retourne le message d'erreur suivant :

IndexError: string index out of range

Pour vérifier le début et la fin d'une chaîne sans avoir à déterminer sur quelle longueur, on peut utiliser "startswith()" et "endswith()", mais c'est moins rapide car faisant appel à une fonction de plus haut niveau. (Référence nécessaire)

if chain.startswith('1234'):
    print('ok')
if chain.endswith('89'):
    print('ok')

Concaténation

modifier

L'opération d'assembler plusieurs petites chaînes pour en construire une plus grande s'appelle concaténation et on la réalise sous Python à l'aide de l'opérateur "+". Exemple :

a = 'Petit poisson'
b = ' deviendra grand'
c = a + b
print(c)
petit poisson deviendra grand

Pour convertir en nombre véritable une chaîne de caractères qui représente un nombre. Exemple :

>>> chaine = '8647'              
>>> print(chaine + 45)
   ==> *** erreur *** on ne peut pas additionner une chaîne et un nombre 

>>> print(int(chaine) + 65)
8712                         # OK : on peut additionner deux nombres

>>> print(chaine + str(65))
864765                       # OK : on peut concaténer deux chaines

Dans cet exemple, la fonction intégrée int() convertit la chaîne en nombre entier, et str() convertit l'entier en chaîne.


Parcours d'une séquence : for... in...

modifier

Il arrive très souvent que l'on doive traiter l'intégralité d'une chaîne caractère par caractère, du premier jusqu'au dernier, pour effectuer à partir de chacun d'eux une opération quelconque. Nous appellerons cette opération un parcours. En nous limitant aux outils Python que nous connaissons déjà, nous pouvons envisager d'encoder un tel parcours sur la base de l'instruction while :

nom = 'Jacqueline'
index = 0
while index < len(nom):
    print(nom[index], '*', end='')   # En Python 2: print(nom[index] + ' *'), 
    index = index + 1

Cette boucle « parcourt » donc la chaîne nom pour en extraire un à un tous les caractères, lesquels sont ensuite imprimés avec interposition d'astérisques. Notez bien que la condition utilisée avec l'instruction while est index < len(nom), ce qui signifie que le bouclage doit s'effectuer jusqu'à ce que l'on soit arrivé à l'indice numéro 9 (la chaîne compte en effet 10 caractères). Nous aurons effectivement traité tous les caractères de la chaîne, puisque ceux-ci sont indicés de zéro à 9.

Le parcours d'une séquence est une opération très fréquente en programmation. Pour en faciliter l'écriture, Python vous propose une structure de boucle plus appropriée, basée sur le couple d'instructions for ... in ... :

Avec ces instructions, le programme ci-dessus devient :

nom = 'Jacqueline'
for character in nom:
    print(character, '*', end='')   # En Python 2: print(character + ' *'),

Comme vous pouvez le constater, cette structure de boucle est plus compacte. Elle vous évite d'avoir à définir et à incrémenter une variable spécifique (un « compteur ») pour gérer l'indice du caractère que vous voulez traiter à chaque itération. La variable caract contiendra successivement tous les caractères de la chaîne, du premier jusqu'au dernier.

L'instruction for permet donc d'écrire des boucles, dans lesquelles l'itération traite successivement tous les éléments d'une séquence donnée. Dans l'exemple ci-dessus, la séquence était une chaîne de caractères. L'exemple ci-après démontre que l'on peut appliquer le même traitement aux listes :

liste = ['chien','chat','crocodile']
for animal in liste:
    print('longueur de la chaîne', animal, '=', len(animal))

L'exécution de ce script donne :

longueur de la chaîne chien = 5
longueur de la chaîne chat = 4
longueur de la chaîne crocodile = 9

L'instruction for est un nouvel exemple d’instruction composée. N'oubliez donc pas le double point obligatoire à la fin de la ligne, et l'indentation du bloc d'instructions qui suit.

Le nom qui suit le mot réservé in est celui de la séquence qu'il faut traiter. Le nom qui suit le mot réservé for est celui que vous choisissez pour la variable destinée à contenir successivement tous les éléments de la séquence. Cette variable est définie automatiquement (c'est-à-dire qu'il est inutile de la définir au préalable), et son type est automatiquement adapté à celui de l'élément de la séquence qui est en cours de traitement.

Exemple :

divers = ['cheval', 3, 17.25, [5, 'Jean']]
for e in divers:
    print(e)

L'exécution de ce script donne :

cheval
3
17.25
[5, 'Jean']

Bien que les éléments de la liste divers soient tous de types différents (une chaîne de caractères, un entier, un réel, une liste), on peut affecter successivement leurs contenus à la variable e, sans qu'il s'ensuive des erreurs (ceci est rendu possible grâce au typage dynamique des variables Python).


Exercices

  1. Écrivez un script qui détermine si une chaîne contient ou non le caractère « e ».
  2. Écrivez un script qui compte le nombre d'occurrences du caractère « e » dans une chaîne.
  3. Écrivez un script qui recopie une chaîne (dans une nouvelle variable), en insérant des astérisques entre les caractères.
    Ainsi par exemple, « gaston » devra devenir « g*a*s*t*o*n »
  4. Écrivez un script qui recopie une chaîne (dans une nouvelle variable) en l'inversant.
    Ainsi par exemple, « zorglub » deviendra « bulgroz ».
  5. En partant de l'exercice précédent, écrivez un script qui détermine si une chaîne de caractères donnée est un palindrome (c'est-à-dire une chaîne qui peut se lire indifféremment dans les deux sens), comme par exemple « radar » ou « s.o.s ».

Solution

  1. # Recherche d'un caractère particulier dans une chaîne
    
    # Chaîne fournie au départ :
    chain = "Monty python flying circus"
    # Caractère à rechercher :
    letter = "e"
    # Recherche proprement dite :
    i = 0   # indice du caractère en cours d'examen
    found = False   # "drapeau" à lever si le caractère recherché est présent
    while i < len(chain):
        if chain[i] == letter:
            found = True
        i = i + 1
    
    # Affichage :
    print(u"Le caractère", letter)  # Le caractère e
    if found == 1:
        print(u"est présent")
    else:
        print(u"est introuvable")
    print(u"dans la chaîne", chain)  # dans la chaîne Monty python flying circus
    
  2. Réfléchissez !
  3. # Insertion d'un caractère d'espacement dans une chaîne
    
    # Chaîne fournie au départ :
    ch = "Gaston"
    # Caractère à insérer :
    cr = "*"
    # Le nombre de caractères à insérer est inférieur d'une unité au
    # nombre de caractères de la chaîne. On traitera donc celle-ci à
    # partir de son second caractère (en omettant le premier).
    lc = len(ch)    # nombre de caractères total
    i = 1           # indice du premier caractère à examiner (le second, en fait)
    nch = ch[0]     # nouvelle chaîne à construire (contient déjà le premier caractère)
    while i < lc:
        nch = nch + cr + ch[i]
        i = i + 1    
    # Affichage :
    print(nch)
    
  4. # Inversion d'une chaîne de caractères
    
    # Chaîne fournie au départ :
    ch = "zorglub"
    lc = len(ch)    # nombre de caractères total
    i = lc - 1      # le traitement commencera à partir du dernier caractère
    nch = ""        # nouvelle chaîne à construire (vide au départ)
    while i >= 0:
        nch = nch + ch[i]
        i = i - 1    
    # Affichage :
    print(nch)
    
  5. Réfléchissez !

Exercices

  1. Dans un conte américain, huit petits canetons s'appellent respectivement : Jack, Kack, Lack, Mack, Nack, Oack, Pack et Qack. Écrivez un script qui génère tous ces noms à partir des deux chaînes suivantes :
    • prefixes = 'JKLMNOPQ'
    • suffixe = 'ack'
    Si vous utilisez une instruction for... in... , votre script ne devrait comporter que deux lignes.
  2. Rechercher le nombre de mots contenus dans une phrase donnée.

Solution

  1. prefixes, suffixe = "JKLMNOPQ", "ack"
    
    for p in prefixes:
        print p + suffixe
    
  2.     # Comptage du nombre de mots dans "chain"
        chain = "Les petits ruisseaux font les grandes rivières"
        if len(chain) == 0:
            print(0)
        nm = 1                  # la chaîne comporte au moins un mot          
        for c in chain:
            if c == " ":        # il suffit de compter les espaces
                nm = nm + 1
        print(nm)
    

Appartenance d'un élément à une séquence : if.. in...

modifier

L'instruction in peut être utilisée indépendamment de for, pour vérifier si un élément donné fait partie ou non d'une séquence. Vous pouvez par exemple vous servir de in pour vérifier si tel caractère alphabétique fait partie d'un groupe bien déterminé :

car = "e"
voyelles = "aeiouyAEIOUY"
if car in voyelles:
    print (car, "est une voyelle")

D'une manière similaire, vous pouvez vérifier l'appartenance d'un élément à une liste :

n = 5
nombrePremiers = [1, 2, 3, 5, 7, 11, 13, 17]
if  n in nombrePremiers:
    print(n, "fait partie de notre liste de nombres premiers")

Cette instruction très puissante effectue donc à elle seule un véritable parcours de la séquence. À titre d'exercice, écrivez les instructions qui effectueraient le même travail à l'aide d'une boucle classique utilisant l'instruction while.

Exercices

  1. Écrivez un script qui affiche « vrai » si un caractère est un chiffre.
  2. Écrivez un script qui affiche « vrai » si un caractère est une majuscule.

Solution

        if character in "0123456789":
            print(True)
        else:
            print(False)
    
  1.     if character in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
            print True
        else:
            print False
    

Les chaînes sont des séquences non modifiables

modifier

Vous ne pouvez pas modifier le contenu d'une chaîne existante. En d'autres termes, vous ne pouvez pas utiliser l'opérateur [] dans la partie gauche d'une instruction d'affectation. Essayez par exemple d'exécuter le petit script suivant (qui cherche à remplacer une lettre dans une chaîne) :

salut = 'bonjour à tous'
salut[0] = 'B'
print (salut)

Au lieu d'afficher « Bonjour à tous », ce script « lève » une erreur du genre : TypeError: object doesn't support item assignment. Cette erreur est provoquée à la deuxième ligne du script. On y essaie de remplacer une lettre par une autre dans la chaîne, mais cela n'est pas permis.

Par contre, le script ci-dessous fonctionne :

salut = 'bonjour à tous'
salut = 'B' + salut[1:]
print (salut)

Dans cet autre exemple, en effet, nous ne modifions pas la chaîne "salut". Nous en recréons une nouvelle avec le même nom à la deuxième ligne du script (à partir d'un morceau de la précédente, soit, mais qu'importe : il s'agit bien d'une nouvelle chaîne).

Les chaînes sont comparables

modifier

Tous les opérateurs de comparaison dont nous avons parlé à propos des instructions de contrôle de flux (c'est-à-dire les instructions if ... elif ... else) fonctionnent aussi avec les chaînes de caractères. Cela vous sera très utile pour trier des mots par ordre alphabétique :

mot = raw_input("Entrez un mot quelconque : ")
if mot < "limonade":
    place = "précède"
elif mot > "limonade":
    place = "suit"
else:
    place = "se confond avec"
print("Le mot", mot, place, "le mot 'limonade' dans l'ordre alphabétique")

Ces comparaisons sont possibles, parce que les caractères alphabétiques qui constituent une chaîne de caractères sont mémorisés dans la mémoire de l'ordinateur sous forme de nombres binaires dont la valeur est liée à la place qu'occupe le caractère dans l'alphabet. Dans le système de codage ASCII, par exemple, A=65, B=66, C=67, etc.


Encodage

modifier

En python 2, pour encoder une chaîne en Unicode, il faut la préfixer par la lettre "u"[1] :

>>> string = u"il était une fois"
>>> print(string)
'il était une fois'

En python 3, les chaînes de caractères sont en Unicode par défaut. Le préfixe u est donc facultatif. Il reste présent et utile si le programme doit pouvoir fonctionner à la fois en Python 2 et en Python 3.

Au sujet des chaînes de caractères, il est important de savoir que deux notions différentes de chaînes de caractères existent en Python.

Pour des raisons historiques dans les versions de Python inférieures à Python 2, on considérait une chaîne de caractère comme une chaîne d'octets. Ceci permettait d'avoir un seul type pour traiter de deux notions différentes, mais pouvait parfois engendrer de la confusion sur le type traité.

  • Le type String contenait à la fois une séquence d'octet et une chaîne de caractères ASCII/UTF-8 (exemple : "Hello World").

Depuis la version 3 de Python, les types chaînes d'octet et chaîne de caractères sont clairement différenciées.

  • Le type chaîne de caractères (classe str) contient des caractères Unicode (exemple: 'xyzzy', "frobozz")
  • Les octets et tableaux d'octets (classes bytes et bytearray) ne contiennent que des octets (l'un est immutable alors que l'autre est mutable). Exemple : b'xyzzy'.

Pour résumer :

Version de Python Python 2 Python 3
Chaîne de caractères unicode
# Classe unicode
s = u"abc"
s     # u'abc'
s[1]  # u"b"
# Classe str
s = "abc"  #  ou  s = u"abc"
s     # 'abc'
s[1]  # "b"
Chaîne d'octets
# Classe str
s = "abc"
s     # 'abc'
s[1]  # "b"
# Classe bytes
s = b"abc"
s     # b'abc'
s[1]  # 98

La différence de comportement est illustrée dans le tableau comparatif ci-dessous.

Code Résultat en Python 2 Résultat en Python 3
a = 'test'
type(a)
b = u'test'
type(b)
c = b'test'
type(c)

str

unicode

str

str

str

bytes
a == b
a == c
b == c
True
True
True
True
False
False

Classement des caractères

modifier

Il est souvent utile de pouvoir déterminer si tel caractère extrait d'une chaîne est une lettre majuscule ou minuscule, ou plus généralement encore, de déterminer s'il s'agit bien d'une lettre, d'un chiffre, ou encore d'un autre caractère typographique.

Nous pouvons bien entendu écrire différentes fonctions pour assurer ces tâches. Une première possibilité consiste à utiliser l'instruction "in". Mais puisque nous savons désormais que les caractères forment une suite bien ordonnée dans le code ASCII, nous pouvons exploiter d'autres méthodes. Par exemple, pour déterminer si on a affaire à une minuscule :

    if 'a' <= character <= 'z' :
        print('bas de casse')
    else:
        print('haut de casse')

Exercices

  1. Écrivez un script qui affiche « vrai » si l'argument transmis est un chiffre (avec une autre méthode que celles exploitées précédemment)
  2. Écrivez un script qui affiche « vrai » si un caractère est une majuscule

Solution

  1.     if character >= "0" and character <= "9":
            print(True)
        else:
            print(False)
    
  2.     if character >= "A" and character <= "Z":
            print(True)
        else:
            print(False)
    

Afin que vous puissiez effectuer plus aisément toutes sortes de traitements sur les caractères, Python met à votre disposition un certain nombre de fonctions prédéfinies :

  • La fonction ord(character) accepte n'importe quel caractère comme argument. En retour, elle fournit le code ASCII correspondant à ce caractère. Ainsi ord('A') renvoie la valeur 65, et ord(u'é') 233.
  • La fonction chr(number) fait exactement le contraire. L'argument qu'on lui transmet doit être un entier compris entre 0 et 255. En retour, on obtient le caractère ASCII correspondant. Ainsi chr(65) renvoie le caractère A.

Exercices

  1. Écrivez un petit script qui affiche une table des codes ASCII. Le programme doit afficher tous les caractères en regard des codes correspondants. À partir de cette table, établissez les relations numériques reliant chaque caractère majuscule à chaque caractère minuscule.
  2. À partir des relations trouvées, écrivez un script qui convertit tous les caractères d'une phrase donnée en capitales.
  3. À partir des mêmes relations, écrivez un script qui convertit tous les caractères d'une phrase en capitales.
  4. Écrivez un script qui compte le nombre de fois qu'apparaît tel caractère (fourni en argument) dans une phrase donnée.
  5. Écrivez un script qui affiche le nombre de voyelles contenues dans une phrase donnée.

Solution

  1. # Table des codes ASCII :
    c = 32          # Premier code ASCII <imprimable>
    while c < 128 : # caractères non accentués seulement 
        print("Code"), c, ":", chr(c), "  ",
        c = c + 1
    
  2. Réfléchissez !
  3. # Convertir majuscules -> minuscules et inversement :
        # Échange les majuscules et les minuscules de "chaine"
        chain = "Ferdinand-Charles de CAMARET"
        newChain = ""                   # chaîne à construire
        for car in chain:
            code = ord(car)
            if car >= "A" and car <= "Z":
                code = code + 32
            elif car >= "a" and car <= "z":
                code = code - 32
            newChain = newChain + chr(code)
        print(newChain)
    
  4. Réfléchissez !
  5. # Comptage de voyelles :
        # Teste si car est une voyelle"
        if character in "AEIOUYaeiouy":
            print(True)
        else:
            print(False)
    
        # Compte les voyelles présentes dans la chaîne "chaine"
        n = 0
        for c in chaine:
            if voyelle(c):
                n = n + 1
        print(n)
    

Méthodes des objets string

modifier

Sous Python, les chaînes de caractères sont des objets. On peut donc effectuer de nombreux traitements dessus en utilisant des méthodes appropriées. En voici quelques-unes, choisies parmi les plus utiles. Mais vous pouvez obtenir la liste complète de toutes les méthodes associées à un objet à l'aide de la fonction intégrée dir('') ou help(str) :

>>> dir('')
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
  • Les fonctions "str()" et "repr()" (pour représentation d'objet) permettent de transformer un objet Python quelconque en chaîne de caractères. Ces deux fonctions sont différentes : "str('chaine')" retournera 'chaine' tandis que "repr('chaine')" retournera "'chaine'".
  • index(c) : retrouve l'index de la première occurrence du caractère "c" dans la chaîne, ou déclenche une erreur si absent (ValueError: substring not found).
>>> foin = "Portez ce vieux whisky au juge blond qui fume"
>>> print (foin.index("w"))
16
  • find(aiguille) : cherche la position d'une sous-chaîne aiguille dans la chaîne, en partant du début.
>>> foin = "Cette leçon vaut bien un fromage, sans doute ?"
>>> aiguille = "fromage"
>>> print(foin.find(aiguille))
25
  • rfind(aiguille) : pareil que "find" mais en partant de la fin (reverse).

<pre

>
>>> foin = "Cette leçon vaut bien deux fromages, dont un fromage râpé ?"
>>> aiguille = "fromage"
>>> print(foin.rfind(aiguille))
46
  • count(aiguille) : compte le nombre de sous-chaînes aiguille dans la chaîne.
>>> foin = "Le héron au long bec emmanché d'un long cou"
>>> aiguille = 'long'
>>> print(foin.count(aiguille))
2
  • lower() : convertit une chaîne en minuscules.
>>> phrase ="ATTENTION : Danger !"
>>> print(phrase.lower())
attention : danger !
  • upper() : convertit une chaîne en majuscules.
>>> phrase = "Merci beaucoup"
>>> print(phrase.upper())
MERCI BEAUCOUP
  • capitalize() : convertit en majuscule la première lettre d'une chaîne.
>>> phrase = "quel beau temps, aujourd'hui !"
>>> print(phrase.capitalize())
"Quel beau temps, aujourd'hui !"
  • swapcase() : convertit toutes les majuscules en minuscules et vice-versa.
>>> phrase = "La CIGALE et la FOURMI"
>>> print(phrase.swapcase())
lA cigale ET LA fourmi
  • strip() : enlève les espaces éventuels au début et à la fin de la chaîne (trime).
>>> phrase = "   Monty Python   "
>>> phrase.strip()
'Monty Python'
  • replace(old, new) : remplace tous les caractères old par des caractères new dans la chaîne.
>>> phrase = "Si ce n'est toi c'est donc ton frère"
>>> print(phrase.replace(" ","_"))
Si_ce_n'est_toi_c'est_donc_ton_frère


Dans la plupart de ces méthodes, il est possible de préciser quelle portion de la chaîne doit être traitée, en ajoutant des arguments supplémentaires.

>>> print(ch9.index("e"))		# cherche à partir du début de la chaîne 
4							# et trouve le premier 'e'
>>> print(ch9.index("e",5))		# cherche seulement à partir de l'indice 5
8							# et trouve le second 'e'
>>> print(ch9.index("e",15))		# cherche à partir du caractère n° 15
29							# et trouve le quatrième 'e'

Références

modifier


Listes

Déclaration

modifier

Les listes sont des séquences, des collections ordonnées d'objets séparés par des virgules. On les déclare avec l'opérateur d'indiçage ([]) :

>> maListe = ['a','b','c']
>> maListe
['a','b','c']

Lecture

modifier

Comme les caractères dans une chaîne, les objets placés dans une liste sont rendus accessibles par l'intermédiaire d'un index (un nombre qui indique l'emplacement de l'objet dans la séquence, à partir de zéro). De plus, le slicing (« découpage en tranches ») permet aussi de dégager une sous-liste en précisant deux index correspondant aux bornes de la plage.

Une sortie indicée donne :

>> maListe[0]
'a'

>> maListe[-1]
'c'

Une séquence donne par slicing :

>> maListe[0:2]
['a','b']

>> maListe[1:]
['b','c']

Les éléments qui constituent une liste peuvent être de types variés :

>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 476, 3.142]
>>> print(jour)
['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 476, 3.142]

Dans cet exemple, en effet, les premiers éléments sont des chaînes de caractères, puis il y a un entier et un réel. À cet égard, le concept de liste est donc différent des tableaux (array) que l'on rencontre les langages de programmation de bas niveau, où tous les éléments doivent être du même type.

Recherche

modifier

Vous pouvez aisément déterminer si un élément fait partie d'une liste à l'aide de l'instruction in :

 print("a" in ["a", "b", "c"])      # True
 print(not "a" in ["a", "b", "c"])  # False

Si l'emplacement de l'élément importe dans la liste :

 print ["a", "b", "c"].index("a") == 0 # True
 print ["a", "b", "c"].index("z")      # ValueError

Modification

modifier

Affectation

modifier

À la différence de ce qui se passe pour les chaînes, qui constituent un type de données non-modifiables, il est possible de changer les éléments individuels d'une liste :

>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 476, 3.142]
>>> jour[5] = jour[5] + 1016
>>> print(jour)
['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 1492, 3.142]

Les exemples ci-dessus devraient attirer votre attention sur le fait qu'une tranche découpée dans une liste est toujours elle-même une liste (même s'il s'agit d'une tranche qui ne contient qu'un seul élément), alors qu'un élément isolé peut contenir n'importe quel type de donnée.

Exemple en deux dimensions :

>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', ['samedi matin', 'samedi après-midi', 'samedi soir'], 'dimanche']
>>> jour[5][0] = "samedi midi"
>>> jour
>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', ['samedi midi', 'samedi après-midi', 'samedi soir'], 'dimanche']

Ainsi, dans l'exemple ci-dessus on remplace le premier élément d'une liste (n° 0), qui est elle-même l'élément n° 5 d'une autre liste.

Opérations

modifier

On peut appliquer aux listes les opérateurs + (concaténation) et * (multiplication) :

>>> fruits = ['orange','citron']
>>> legumes = ['poireau','oignon','tomate']
>>> fruits + legumes
['orange', 'citron', 'poireau', 'oignon', 'tomate']
>>> fruits * 3
['orange', 'citron', 'orange', 'citron', 'orange', 'citron']

L'opérateur * est particulièrement utile pour créer une liste de "n" éléments identiques :

>>> sept_zeros = [0]*7
>>> sept_zeros
[0, 0, 0, 0, 0, 0, 0]

Techniques de slicing avancées pour modifier une liste

modifier

Insertion

modifier

Insertion d'un ou plusieurs éléments n'importe où dans une liste :

>>> mots = ['jambon', 'fromage', 'confiture', 'chocolat']
>>> mots[2:2] = ["miel"]
>>> mots
['jambon', 'fromage', 'miel', 'confiture', 'chocolat']
>>> mots[5:5] = ['saucisson', 'ketchup']
>>> mots
['jambon', 'fromage', 'miel', 'confiture', 'chocolat', 'saucisson', 'ketchup']

Pour utiliser cette technique, vous devez prendre en compte les particularités suivantes :

  • Si vous utilisez l'opérateur [ ] à la gauche du signe égale pour effectuer une insertion ou une suppression d'élément(s) dans une liste, vous devez obligatoirement y indiquer une « tranche » dans la liste cible (c'est-à-dire deux index réunis par le symbole ":"), et non un élément isolé dans cette liste.
  • L'élément que vous fournissez à la droite du signe égale doit lui-même être une liste. Si vous n'insérez qu'un seul élément, il vous faut donc le présenter entre crochets pour le transformer d'abord en une liste d'un seul élément. Notez bien que l'élément mots[1] n'est pas une liste (c'est la chaîne fromage), alors que l'élément mots[1:3] en est une.

Suppression

modifier

Suppression / remplacement d'éléments :

>>> mots[2:5] = []                       # [] désigne une liste vide
>>> mots
['jambon','fromage','saucisson', 'ketchup']
>>> mots[1:3] = ['salade']
>>> mots
['jambon', 'salade', 'ketchup']
>>> mots[1:] = ['mayonnaise', 'poulet', 'tomate']
>>> mots
['jambon', 'mayonnaise', 'poulet', 'tomate']
  • À la première ligne de cet exemple, nous remplaçons la tranche [2:5] par une liste vide, ce qui correspond à un effacement.
  • À la quatrième ligne, nous remplaçons une tranche par un seul élément. (Notez encore une fois que cet élément doit lui-même être « présenté » comme une liste).
  • À la 7e ligne, nous remplaçons une tranche de deux éléments par une autre qui en comporte 3.

Différence

modifier

Pour obtenir la différence entre deux listes :

a = ['jambon','fromage','saucisson', 'ketchup']
b = ['jambon', 'mayonnaise', 'poulet', 'tomate']
print([item for item in a if item not in b])
# ['fromage', 'saucisson', 'ketchup']

Intersection

modifier

Pour l'intersection entre deux listes (en préservant l'ordre des éléments y compris leurs doublons), on applique la différence de la différence :

a = ['jambon','fromage','saucisson', 'ketchup']
b = ['jambon', 'mayonnaise', 'poulet', 'tomate']
dif = [item for item in a if item not in b]
print [item for item in a if item not in dif]
# ['jambon']

Considérons que vous disposez d'une liste fable que vous souhaitez recopier dans une nouvelle variable que vous appellerez phrase. La première idée qui vous viendra à l'esprit sera certainement d'écrire une simple affectation telle que :

>>> phrase = fable

En procédant ainsi, sachez que vous ne créez pas une véritable copie. À la suite de cette instruction, il n'existe toujours qu'une seule liste dans la mémoire de l'ordinateur. Ce que vous avez créé est seulement une nouvelle référence vers cette liste. Essayez par exemple :

>>> fable = ['Je','plie','mais','ne','romps','point']
>>> phrase = fable
>>> fable[4] ='casse'
>>> phrase
['Je', 'plie', 'mais', 'ne', 'casse', 'point']

Si la variable phrase contenait une véritable copie de la liste, cette copie serait indépendante de l'original et ne devrait donc pas pouvoir être modifiée par une instruction telle que celle de la troisième ligne, qui s'applique à la variable fable. Vous pouvez encore expérimenter d'autres modifications, soit au contenu de fable, soit au contenu de phrase. Dans tous les cas, vous constaterez que les modifications de l'une sont répercutées dans l'autre, et vice-versa.

En fait, les noms fable et phrase désignent tous deux un seul et même objet en mémoire. Pour décrire cette situation, les informaticiens diront que le nom phrase est un alias du nom fable.

 
Schéma de la copie d'une liste.

Nous verrons plus tard l'utilité des alias. Pour l'instant, nous voudrions disposer d'une technique pour effectuer une véritable copie d'une liste. Avec les notions vues précédemment, vous devriez pouvoir en trouver une par vous-même.

 Python vous autorise à « étendre » une longue instruction sur plusieurs lignes, si vous continuez à encoder quelque chose qui est délimité par une paire de parenthèses, de crochets ou d'accolades. Vous pouvez traiter ainsi des expressions parenthésées, ou encore la définition de longues listes, de grands tuples ou de grands dictionnaires. Le niveau d'indentation n'a pas d'importance : l'interpréteur détecte la fin de l'instruction, là où la paire syntaxique est refermée.

Cette fonctionnalité vous permet d'améliorer la lisibilité de vos programmes. Exemple :

couleurs = ['noir', 'brun', 'rouge',
            'orange', 'jaune', 'vert',
            'bleu', 'violet', 'gris', 'blanc']


Méthodes

modifier

Sous Python, les listes sont des objets à part entière, et vous pouvez donc leur appliquer un certain nombre de méthodes particulièrement efficaces, après l'opérateur "." :

>>> nombres = [17, 38, 10, 25, 72]

>>> nombres.sort()                 # trier la liste
>>> nombres
[10, 17, 25, 38, 72]

>>> nombres.append(12)             # ajouter un élément à la fin
>>> nombres
[10, 17, 25, 38, 72, 12]

>>> nombres.reverse()              # inverser l'ordre des éléments
>>> nombres
[12, 72, 38, 25, 17, 10]

>>> nombres.index(17)              # retrouver l'index d'un élément
4

>>> nombres.remove(38)             # enlever (effacer) un élément
>>> nombres
[12, 72, 25, 17, 10]

append() (ajouter) : l'exemple suivant qui fait appel à la méthode "append" de l'objet "liste" (déclarée vide) illustre ce concept.

Il s'agit de remplir la hotte du Père Noël.

 #!/usr/bin/python
 # -*- coding: iso8859-1 -*-
 
 # on prépare une liste encore vide
 cadeaux = []
 
 # on va ajouter des éléments à la liste
 unCadeau = ""
 
 # la suite des éléments à introduire dans la liste est définie par l'utilisateur
 # lorsqu'il a terminé, l'utilisateur indique le mot "fin" qui ne sera pas introduit dans la liste
 while unCadeau <> "fin":
 	unCadeau = raw_input ("Père Noël, je voudrais que tu m'apportes ")
        # si l'utilisateur n'a pas frappé "fin", le mot est ajouté à la liste
 	if unCadeau <> "fin":
 		cadeaux.append(unCadeau)
 
 # finalement, on écrit la suite des éléments introduits dans la liste
 for chaqueCadeau in cadeaux:
 	print chaqueCadeau

split() : convertit une chaîne en une liste de sous-chaînes. On peut choisir le caractère séparateur en le fournissant comme argument, sinon c'est un espace, par défaut.

>>> chaine ="Votez pour moi"
>>> tableau = chaine.split()
>>> print tableau
['Votez', 'pour', 'moi']

>>> chaine = "Cet exemple, parmi d'autres, peut encore servir"
>>> chaine.split(",")
['Cet exemple', " parmi d'autres", ' peut encore servir']

join(liste) : rassemble une liste de chaînes en une seule (Cette méthode fait donc l'inverse de la précédente). Attention : la chaîne à laquelle on applique cette méthode est celle qui servira de séparateur (un ou plusieurs caractères) ; l'argument transmis est la liste des chaînes à rassembler.

>>> tableau = ["Salut", "les", "copains"]
>>> print  " ".join(tableau)
Salut les copains
>>> print  "___".join(tableau)
Salut___les___copains

pop(i) retire et renvoie l'élément de la liste d'index i. Si i est vide, il traite le dernier élément.

>>> list = [1, 2, 3, 4]

>>> print(list.pop(0))
1
>>> list
[2, 3, 4]

>>> print(list.pop())
4
>>>list
[2, 3]


Fonctions

modifier

La fonction intégrée len(), que nous avons déjà rencontrée à propos des chaînes, s'applique aussi aux listes. Elle renvoie le nombre d'éléments présents dans la liste :

>>> len(jour)
7

Supposons par exemple que vous voulez créer une liste B qui contienne le même nombre d'éléments qu'une autre liste A. Vous pouvez obtenir ce résultat de différentes manières, mais l'une des plus simples consistera à effectuer : B = [0]*len(A).

Une autre fonction intégrée permet de supprimer d'une liste un élément ou plusieurs éléments quelconques à partir de leurs index. Il s'agit de la fonction del() :

>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 476, 3.142]

>>> del(jour[5:7])
>>> print(jour)
['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi']

>>> del(jour[0])
>>> print(jour)
['mardi', 'mercredi', 'jeudi', 'vendredi']
 notez bien la différence entre la méthode remove() et la fonction del() : del travaille avec un indice ou une tranche d'indices, tandis que remove() recherche une valeur (si plusieurs éléments de la liste possèdent la même valeur, seul le premier est effacé).

min et max

modifier
  • min(liste) : minimum d'une liste (élément ayant la plus petite valeur).
  • max(liste) : maximum d'une liste.
>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi']

>>> min(jour)
'jeudi'

>>> max(jour)
'vendredi'

Si vous devez manipuler des séquences de nombres, vous pouvez les créer très aisément à l'aide de cette fonction :

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Sous python 3.6: print(list(range(10))) La fonction range() génère une liste de nombres entiers de valeurs croissantes. Si vous appelez range() avec un seul argument, la liste contiendra un nombre de valeurs égal à l'argument fourni, mais en commençant à partir de zéro (c'est-à-dire que range(n) génère les nombres de 0 à n-1).

Notez bien que l'argument fourni n'est jamais dans la liste générée.

On peut aussi utiliser range() avec deux, ou même trois arguments séparés par des virgules, afin de générer des séquences de nombres plus spécifiques :

>>> range(5,13)
[5, 6, 7, 8, 9, 10, 11, 12]
>>> range(3,16,3)
[3, 6, 9, 12, 15]

Si vous avez du mal à assimiler l'exemple ci-dessus, considérez que range() attend toujours trois arguments, que l'on pourrait intituler FROM, TO et STEP. FROM est la première valeur à générer, TO est la dernière (ou plutôt la dernière + un), et STEP le « pas » à sauter pour passer d'une valeur à la suivante. S'ils ne sont pas fournis, les paramètres FROM et STEP prennent leurs valeurs par défaut, qui sont respectivement 0 et 1.

Parcours d'une liste à l'aide de for, range() et len()

modifier

L'instruction for est l'instruction idéale pour parcourir une liste :

>>> prov = ['La','raison','du','plus','fort','est','toujours','la','meilleure']
>>> for mot in prov:
       print mot,
La raison du plus fort est toujours la meilleure

Il est très pratique de combiner les fonctions range() et len() pour obtenir automatiquement tous les indices d'une séquence (liste ou chaîne). Exemple :

fable = ['Maître','Corbeau','sur','un','arbre','perché']
for index in range(len(fable)):
    print index, fable[index]

Mais il existe également une syntaxe adaptée à cela :

for (cle, valeur) in enumerate(fable):
    print(cle, valeur)

L'exécution de ce script donne le résultat :

0 Maître
1 Corbeau
2 sur
3 un
4 arbre
5 perché

Tableau à trois lignes :

monTableau = range(1, 5)
monTableau[1] = u'ligne 1'
monTableau[2] = u'ligne 2'
monTableau[3] = u'ligne 3'

for ligne in range(1, 4):
    print(monTableau[ligne])

Tableau à deux dimensions :

ligne = 3
colonne = 2
monTableau = [[0] * (colonne+1) for _ in range(ligne+1)]
monTableau[1][1] = u'1.1'
monTableau[1][2] = u'1.2'
monTableau[2][1] = u'2.1'
monTableau[2][2] = u'2.2'
monTableau[3][1] = u'3.1'
monTableau[3][2] = u'3.2'

for l in range(1, ligne + 1):
    for c in range(1, colonne + 1):
        print(monTableau[l][c])

Une conséquence du typage dynamique

modifier

Le type de la variable utilisée avec l'instruction "for" est redéfini continuellement au fur et à mesure du parcours : même si les éléments d'une liste sont de types différents, on peut parcourir cette liste à l'aide de "for" sans qu'il ne s'ensuive une erreur, car le type de la variable de parcours s'adapte automatiquement à celui de l'élément en cours de lecture. Exemple :

>>> divers = [3, 17.25, [5, 'Jean'], 'Linux is not Windoze']
>>> for item in divers:
        print item, type(item)
3 <type 'int'>
17.25 <type 'float'>
[5, 'Jean'] <type 'list'>
Linux is not Windoze <type 'str'>

La plupart des programmes d'ordinateur font exactement la même chose chaque fois qu'on les exécute. De tels programmes sont dits déterministes. Le déterminisme est certainement une bonne chose : nous voulons évidemment qu'une même série de calculs appliquée aux mêmes données initiales aboutisse toujours au même résultat. Pour certaines applications, cependant, nous pouvons souhaiter que l'ordinateur soit imprévisible. Le cas des jeux constitue un exemple évident, mais il en existe bien d'autres.

Contrairement aux apparences, il n'est pas facile du tout d'écrire un algorithme qui soit réellement non-déterministe (c'est-à-dire qui produise un résultat totalement imprévisible). Il existe cependant des techniques mathématiques permettant de simuler plus ou moins bien l'effet du hasard. Des livres entiers ont été écrits sur les moyens de produire ainsi un hasard « de bonne qualité ». Nous n'allons évidemment pas développer ici une telle question, mais rien ne vous empêche de consulter à ce sujet votre professeur de mathématiques.

Dans son module random, Python propose toute une série de fonctions permettant de générer des nombres aléatoires qui suivent différentes distributions mathématiques. Nous n'examinerons ici que quelques-unes d'entre elles. Veuillez consulter la documentation en ligne pour découvrir les autres. Vous pouvez importer toutes les fonctions du module par :

>>> from random import *

Pour créer une liste de nombres réels aléatoires, de valeur comprise entre zéro et un :

>>> s = [0]*tailleListe
    for i in range(tailleListe):
        s[i] = random()
    print(s)

Vous pouvez constater que nous avons pris le parti de construire d'abord une liste de zéros de taille n, et ensuite de remplacer les zéros par des nombres aléatoires.

Exercices

  1. Réécrivez la fonction list_aleat() ci-dessus, en utilisant la méthode append() pour construire la liste petit à petit à partir d'une liste vide (au lieu de remplacer les zéros d'une liste préexistante comme nous l'avons fait).
  2. Écrivez une fonction imprime_liste() qui permette d'afficher ligne par ligne tous les éléments contenus dans une liste de taille quelconque. Le nom de la liste sera fourni en argument. Utilisez cette fonction pour imprimer la liste de nombres aléatoires générés par la fonction list_aleat(). Ainsi par exemple, l'instruction imprime_liste(liste_aleat(8)) devra afficher une colonne de 8 nombres réels aléatoires.

Solution

  1. Réfléchissez !
  2. Réfléchissez !

Les nombres ainsi générés sont-ils vraiment aléatoires ? C'est difficile à dire. Si nous ne tirons qu'un petit nombre de valeurs, nous ne pouvons rien vérifier. Par contre, si nous utilisons un grand nombre de fois la fonction random(), nous nous attendons à ce que la moitié des valeurs produites soient plus grandes que 0,5 (et l'autre moitié plus petites).

Affinons ce raisonnement. Les valeurs tirées sont toujours dans l'intervalle 0-1. Partageons cet intervalle en 4 fractions égales : de 0 à 0,25 , de 0,25 à 0,5 , de 0,5 à 0,75 , et de 0,75 à 1. Si nous tirons un grand nombre de valeurs au hasard, nous nous attendons à ce qu'il y en ait autant qui se situent dans chacune de nos 4 fractions. Et nous pouvons généraliser ce raisonnement à un nombre quelconque de fractions, du moment qu'elles soient égales.

Exercices

  1. Vous allez écrire un programme destiné à vérifier le fonctionnement du générateur de nombres aléatoires de Python en appliquant la théorie exposée ci-dessus. Votre programme devra donc : a) Demander à l'utilisateur le nombre de valeurs à tirer au hasard à l'aide de la fonction random(). Il serait intéressant que le programme propose un nombre par défaut (1000 par exemple). b) Demander à l'utilisateur en combien de fractions il souhaite partager l'intervalle des valeurs possibles (c'est-à-dire l'intervalle de 0 à 1). Ici aussi, il faudrait proposer un nombre de par défaut (5 fractions, par exemple). Vous pouvez également limiter le choix de l'utilisateur à un nombre compris entre 2 et le 1/10e du nombre de valeurs tirées au hasard. c) Construire une liste de N compteurs (N étant le nombre de fractions souhaitées). Chacun d'eux sera évidemment initialisé à zéro. d) Tirer au hasard toutes les valeurs demandées, à l'aide de la fonction random(), et mémoriser ces valeurs dans une liste. e) Mettre en œuvre un parcours de la liste des valeurs tirées au hasard (boucle), et effectuer un test sur chacune d'elles pour déterminer dans quelle fraction de l'intervalle 0-1 elle se situe. Incrémenter de une unité le compteur correspondant. f) Lorsque c'est terminé, afficher l'état de chacun des compteurs.

Solution

  1. # Test du générateur de nombres aléatoires :
    from random import random           # tire au hasard un réel entre 0 et 1
    
    n = raw_input("Nombre de valeurs à tirer au hasard (défaut = 1000) : ")
    if n == "":
        nVal =1000
    else:
        nVal = int(n)
    
    n = raw_input("Nombre de fractions dans l'intervalle 0-1 (entre 2 et "
                  + str(nVal/10) + ", défaut =5) : ")
    if n == "":
        nFra =5
    else:
        nFra = int(n)
    
    if nFra < 2:
        nFra =2
    elif nFra > nVal/10:
        nFra = nVal/10
    
    print "Tirage au sort des", nVal, "valeurs ..."
    listVal = [0]*nVal                      # créer une liste de zéros
    for i in range(nVal):                   # puis modifier chaque élément
        listVal[i] = random()
    
    print "Comptage des valeurs dans chacune des", nFra, "fractions ..."
    listCompt = [0]*nFra                    # créer une liste de compteurs
    
    # parcourir la liste des valeurs :
    for valeur in listVal:
        # trouver l'index de la fraction qui contient la valeur :    
        index = int(valeur*nFra)
        # incrémenter le compteur correspondant :
        listCompt[index] = listCompt[index] +1
    
    # afficher l'état des compteurs :
    for compt in listCompt:
        print compt,
    

Exemple de résultats affichés par un programme de ce type

modifier
Nombre de valeurs à tirer au hasard (défaut = 1000) : 100
Nombre de fractions dans l'intervalle 0-1 (entre 2 et 10, défaut =5) : 5
Tirage au sort des 100 valeurs ...
Comptage des valeurs dans chacune des 5 fractions ...
11 30 25 14 20 
Nombre de valeurs à tirer au hasard (défaut = 1000) : 10000
Nombre de fractions dans l'intervalle 0-1 (entre 2 et 1000, défaut =5) : 5
Tirage au sort des 10000 valeurs ...
Comptage des valeurs dans chacune des 5 fractions ...
1970 1972 2061 1935 2062

Une bonne approche de ce genre de problème consiste à essayer d'imaginer quelles fonctions simples vous pourriez écrire pour résoudre l'une ou l'autre partie du problème, puis de les utiliser dans un ensemble plus vaste.

Par exemple, vous pourriez chercher à définir d'abord une fonction numeroFraction() qui servirait à déterminer dans quelle fraction de l'intervalle 0-1 une valeur tirée se situe. Cette fonction attendrait deux arguments (la valeur tirée, le nombre de fractions choisi par l'utilisateur) et fournirait en retour l'index du compteur à incrémenter (c'est-à-dire le n° de la fraction correspondante). Il existe peut-être un raisonnement mathématique simple qui permette de déterminer l'index de la fraction à partir de ces deux arguments. Pensez notamment à la fonction intégrée int(), qui permet de convertir un nombre réel en nombre entier en éliminant sa partie décimale.

Si vous ne trouvez pas, une autre réflexion intéressante serait peut-être de construire d'abord une liste contenant les valeurs « pivots » qui délimitent les fractions retenues (par exemple 0 – 0,25 – 0,5 – 0,75 - 1 dans le cas de 4 fractions). La connaissance de ces valeurs faciliterait peut-être l'écriture de la fonction numeroFraction() que nous souhaitons mettre au point.

Si vous disposez d'un temps suffisant, vous pouvez aussi réaliser une version graphique de ce programme, qui présentera les résultats sous la forme d'un histogramme (diagramme « en bâtons »).

Tirage au hasard de nombres entiers

modifier

Lorsque vous développerez des projets personnels, il vous arrivera fréquemment de souhaiter pouvoir disposer d'une fonction qui permette de tirer au hasard un nombre entier entre certaines limites. Par exemple, si vous voulez écrire un programme de jeu dans lequel des cartes à jouer sont tirées au hasard (à partir d'un jeu ordinaire de 52 cartes), vous aurez certainement l'utilité d'une fonction capable de tirer au hasard un nombre entier compris entre 1 et 52.

Vous pouvez pour ce faire utiliser la fonction randrange() du module random.

Cette fonction peut être utilisée avec 1, 2 ou 3 arguments.

Avec un seul argument, elle renvoie un entier compris entre zéro et la valeur de l'argument diminué d'une unité. Par exemple, randrange(6) renvoie un nombre compris entre 0 et 5.

Avec deux arguments, le nombre renvoyé est compris entre la valeur du premier argument et la valeur du second argument diminué d'une unité. Par exemple, randrange(2, 8) renvoie un nombre compris entre 2 et 7.

Si l'on ajoute un troisième argument, celui-ci indique que le nombre tiré au hasard doit faire partie d'une série limitée d'entiers, séparés les uns des autres par un certain intervalle, défini lui-même par ce troisième argument. Par exemple, randrange(3, 13, 3) renverra un des nombres de la série 3, 6, 9, 12 :

>>> for i in range(15):
        print random.randrange(3,13,3),

3 12 6 9 6 6 12 6 3 6 9 3 6 12 12

Exercices

  1. Écrivez un script qui tire au hasard des cartes à jouer. Le nom de la carte tirée doit être correctement présenté, « en clair ». Le programme affichera par exemple : Frappez <Enter> pour tirer une carte :
    Dix de Trèfle
    Frappez <Enter> pour tirer une carte :
    As de Carreau
    Frappez <Enter> pour tirer une carte :
    Huit de Pique
    Frappez <Enter> pour tirer une carte :
    etc ...

Solution

  1. # Tirage de cartes
    from random import randrange
    
    couleurs = ['Pique', 'Trèfle', 'Carreau', 'Cœur']
    valeurs = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'valet', 'dame', 'roi', 'as']
    
    # Construction de la liste des 52 cartes :
    carte =[]
    for coul in couleurs:
         for val in valeurs:
              carte.append("%s de %s" % (str(val), coul))
    
    # Tirage au hasard :
    while 1:
         k = raw_input("Frappez <c> pour tirer une carte, <Enter> pour terminer ") 
         if k =="":
              break
         r = randrange(52)
         print carte[r]
    

Permet d'appliquer une fonction à toutes les entrées d'une liste. Par exemple pour les trimer :

l = [' ma super ligne 1\n', ' ma super ligne 2\n']
l = map(str.strip, l)
print l
# ['ma super ligne 1', 'ma super ligne 2']

Exercices

modifier

Exercices

  1. Soient les listes suivantes : t1 = [31,28,31,30,31,30,31,31,30,31,30,31]
    t2 = ['Janvier','Février','Mars','Avril','Mai','Juin',
    'Juillet','Août','Septembre','Octobre','Novembre','Décembre'] Écrivez un petit programme qui insère dans la seconde liste tous les éléments de la première, de telle sorte que chaque nom de mois soit suivi du nombre de jours correspondant : ['Janvier',31,'Février',28,'Mars',31, etc.].
  2. Créez une liste A contenant quelques éléments. Effectuez une vraie copie de cette liste dans une nouvelle variable B. Suggestion : créez d'abord une liste B de même taille que A mais ne contenant que des zéros. Remplacez ensuite tous ces zéros par les éléments tirés de A.
  3. Même question, mais autre suggestion : créez d'abord une liste B vide. Remplissez-la ensuite à l'aide des éléments de A ajoutés l'un après l'autre.
  4. Même question, autre suggestion encore : pour créer la liste B, découpez dans la liste A une tranche incluant tous les éléments (à l'aide de l'opérateur [:]).
  5. Un nombre premier est un nombre qui n'est divisible que par un et par lui-même. Écrivez un programme qui établisse la liste de tous les nombres premiers compris entre 1 et 1000, en utilisant la méthode du crible d'Ératosthène :
    • Créez une liste de 1000 éléments, chacun initialisé à la valeur 1.
    • Parcourez cette liste à partir de l'élément d'indice 2 : si l'élément analysé possède la valeur 1, mettez à zéro tous les autres éléments de la liste, dont les indices sont des multiples entiers de l'indice auquel vous êtes arrivé.
    Lorsque vous aurez parcouru ainsi toute la liste, les indices des éléments qui seront restés à 1 seront les nombres premiers recherchés. En effet, à partir de l'indice 2, vous annulez tous les éléments d'indices pairs : 4, 6, 8, 10, etc. Avec l'indice 3, vous annulez les éléments d'indices 6, 9, 12, 15, etc., et ainsi de suite. Seuls resteront à 1 les éléments dont les indices sont effectivement des nombres premiers.

Solution

  1. # Insertion de nouveaux éléments dans une liste existante
    
    t1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    t2 = ['Janvier','Février','Mars','Avril','Mai','Juin',
          'Juillet','Août','Septembre','Octobre','Novembre','Décembre']
    
    c, d = 1, 0
    while d < 12 :
         t2[c:c] = [t1[d]]       # ! l'élément inséré doit être une liste
         c, d = c+2, d+1
    </pre>
    </li>
    
    <li>Réfléchissez !</li>
    
    <li>Réfléchissez !</li>
    
    <li>Réfléchissez !</li>
    
    <li>
    <syntaxhighlight lang=python>
    # Crible d’Ératosthène pour rechercher les nombres premiers de 1 à 999
    
    # Créer une liste de 1000 éléments 1 (leurs indices vont de 0 à 999) :
    lst = [1]*1000           
    # Parcourir la liste à partir de l'élément d'indice 2:
    for i in range(2,1000):
        # Mettre à zéro les éléments suivants dans la liste,
        # dont les indices sont des multiples de i :
        for j in range(i*2, 1000, i):
            lst[j] = 0
    
    # Afficher les indices des éléments restés à 1 (on ignore l'élément 0) :
    for i in range(1,1000):
        if lst[i]:
            print i,
    

Exercices

  1. Déterminez vous-même ce qui se passe lorsque l'un ou l'autre des indices de découpage est erroné, et décrivez cela le mieux possible (si le second indice est plus petit que le premier, par exemple, ou bien si le second indice est plus grand que la taille de la chaîne).
  2. Découpez une grande chaîne en fragments de cinq caractères chacun. Rassemblez ces morceaux dans l'ordre inverse.
  3. Tâchez d'écrire un script qui fera exactement le contraire de ce que fait l'opérateur d'indexage ([]) : au lieu de partir d'un index donné pour retrouver le caractère correspondant, il devra retrouver l'index correspondant à un caractère donné, à partir du nom de la chaîne à traiter et du caractère à trouver. Exemple : pour "Juliette & Roméo", "&" il devra afficher : 9, ou -1 si le caractère est introuvable.
  4. Améliorez le script en lui ajoutant une troisième variable : l'index à partir duquel la recherche doit s'effectuer dans la chaîne. Ainsi par exemple, pour : "César & Cléopâtre", "r", 5, il devra afficher : 15 (et non 4 !)
  5. Écrivez un script qui compte le nombre d'occurrences d'un caractère donné dans une chaîne. Ainsi, pour "ananas au jus", "a" il devra afficher : 4.

Solution

  1. IndexError: list index out of range
  2. # Découpage d'une chaîne en fragments :
    chain ="abcdefghijklmnopqrstuvwxyz123456789"
    n = 5
    
    # Découpage de "chain" en une liste de fragments de n caractères"
    d, f = 0, n             # indices de début et de fin de fragment
    tt = []                 # liste à construire
    while d < len(chain):
    	if f > len(chain):  # on ne peut pas découper au-delà de la fin
    		f = len(chain)
    	fr = chain[d:f]     # découpage d'un fragment
    	tt.append(fr)       # ajout du fragment à la liste
    	d, f = f, f + n      # indices suivants 
    print(tt)
    
    # Rassemble les éléments de la liste tt dans l'ordre inverse"
    chain = ""              # chaîne à construire
    i = len(tt)             # on commence par la fin de la liste
    while i > 0 :
    	i = i - 1           # le dernier élément possède l'indice n - 1
    	chain = chain + tt[i]
    print(chain)
    
  3. # Rechercher l'indice d'un caractère dans une chaîne
    chain, car = "Coucou c'est moi", "z"
    start = 0
    
    # Trouve l'indice du caractère car dans "chain"
    i = start
    while i < len(chain):
    	if chain[i] == car:
    		print(i)	# le caractère est trouvé -> on termine
    	i = i + 1
    print(-1)       		# toute la chaîne a été scannée sans succès 
    
    # Autres tests :
    chain, car = "Juliette & Roméo", "&"
    chain, car, start = "César & Cléopâtre", "r", 5
    
  4. Réfléchissez !
  5. Réfléchissez !

Exercices

  1. Soient les listes suivantes :
    t1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    t2 = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',
          'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
    
    Écrivez un petit programme qui crée une nouvelle liste t3. Celle-ci devra contenir tous les éléments des deux listes en les alternant, de telle manière que chaque nom de mois soit suivi du nombre de jours correspondant : ['Janvier',31,'Février',28,'Mars',31, etc.].
  2. Écrivez un programme qui affiche « proprement » tous les éléments d'une liste. Si on l'appliquait par exemple à la liste t2 de l'exercice ci-dessus, on devrait obtenir :
    Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre Décembre
    
  3. Écrivez un programme qui recherche le plus grand élément présent dans une liste donnée. Par exemple, si on l'appliquait à la liste [32, 5, 12, 8, 3, 75, 2, 15], ce programme devrait afficher :
    le plus grand élément de cette liste a la valeur 75.
    
  4. Écrivez un programme qui analyse un par un tous les éléments d'une liste de nombres (par exemple celle de l'exercice précédent) pour générer deux nouvelles listes. L'une contiendra seulement les nombres pairs de la liste initiale, et l'autre les nombres impairs. Par exemple, si la liste initiale est celle de l'exercice précédent, le programme devra construire une liste pairs qui contiendra [32, 12, 8, 2], et une liste impairs qui contiendra [5, 3, 75, 15]. Astuce : pensez à utiliser l'opérateur modulo (%) déjà cité précédemment.
  5. Écrivez un programme qui analyse un par un tous les éléments d'une liste de mots (par exemple : ['Jean', 'Maximilien', 'Brigitte', 'Sonia', 'Jean-Pierre', 'Sandra'] pour générer deux nouvelles listes. L'une contiendra les mots comportant moins de 6 caractères, l'autre les mots comportant 6 caractères ou davantage.

Solution

  1. # Combinaison de deux listes en une seule
    
    # Listes fournies au départ :
    t1 = [31,28,31,30,31,30,31,31,30,31,30,31]
    t2 = ['Janvier','Février','Mars','Avril','Mai','Juin',
          'Juillet','Août','Septembre','Octobre','Novembre','Décembre']
    # Nouvelle liste à construire (vide au départ) :
    t3 = []
    # Boucle de traitement :
    i = 0
    while i < len(t1):
        t3.append(t2[i])
        t3.append(t1[i])
        i = i + 1
    
    # Affichage :
    print t3
    
  2. # Affichage des éléments d'une liste
    
    # Liste fournie au départ :
    t2 = ['Janvier','Février','Mars','Avril','Mai','Juin',
          'Juillet','Août','Septembre','Octobre','Novembre','Décembre']
    # Affichage :
    i = 0
    while i < len(t2):
        print t2[i],
        i = i + 1
    
  3. # Recherche du plus grand élément d'une liste
    
    # Liste fournie au départ :
    tt = [32, 5, 12, 8, 3, 75, 2, 15]
    # Au fur et à mesure du traitement de la liste, on mémorisera dans
    # la variable ci-dessous la valeur du plus grand élément déjà trouvé :
    max = 0
    # Examen de tous les éléments :
    i = 0
    while i < len(tt):
        if tt[i] > max:
            max = tt[i]         # mémorisation d'un nouveau maximum
        i = i + 1
    # Affichage :
    print "Le plus grand élément de cette liste a la valeur", max
    
  4. # Séparation des nombres pairs et impairs
    
    # Liste fournie au départ :
    tt = [32, 5, 12, 8, 3, 75, 2, 15]
    pairs = []
    impairs = []
    # Examen de tous les éléments :
    i = 0
    while i < len(tt):
        if tt[i] % 2 == 0:
            pairs.append(tt[i])
        else:
            impairs.append(tt[i])
        i = i + 1
    # Affichage :
    print "Nombres pairs :", pairs
    print "Nombres impairs :", impairs
    
  5. Réfléchissez !

Exercices

  1. Écrivez un script qui génère la liste des carrés et des cubes des nombres de 20 à 40.
  2. Écrivez un script qui crée automatiquement la liste des sinus des angles de 0° à 90° , par pas de 5°. Attention : la fonction sin() du module math considère que les angles sont fournis en radians (360° = 2 p radians)
  3. Écrivez un script qui permette d'obtenir à l'écran les 15 premiers termes des tables de multiplication par 2, 3, 5, 7, 11, 13, 17, 19 (ces nombres seront placés au départ dans une liste) sous la forme d'une table semblable à la suivante :
    2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
    3 6 9 12 15 18 21 24 27 30 33 36 39 42 45
    5 10 15 20 25 30 35 40 45 50 55 60 65 70 75
    etc.
  4. Soit la liste suivante :
    ['Jean-Michel', 'Marc', 'Vanessa', 'Anne', 'Maximilien', 'Alexandre-Benoît', 'Louise']
    Écrivez un script qui affiche chacun de ces noms avec le nombre de caractères correspondant.
  5. Vous disposez d'une liste de nombres entiers quelconques, certains d'entre eux étant présents en plusieurs exemplaires. Écrivez un script qui recopie cette liste dans une autre, en omettant les doublons. La liste finale devra être triée.
  6. Écrivez un script qui recherche le mot le plus long dans une phrase donnée (l'utilisateur du programme doit pouvoir entrer une phrase de son choix).
  7. Écrivez un script capable d'afficher la liste de tous les jours d'une année imaginaire, laquelle commencerait un Jeudi. Votre script utilisera lui-même trois listes : une liste des noms de jours de la semaine, une liste des noms des mois, et une liste des nombres de jours que comportent chacun des mois (ne pas tenir compte des années bissextiles).
    Exemple de sortie :
    Jeudi 1 Janvier Vendredi 2 Janvier Samedi 3 Janvier Dimanche 4 Janvier
    ... et ainsi de suite jusqu'au Jeudi 31 Décembre.
  8. Vous avez à votre disposition un fichier texte qui contient un certain nombre de noms d'élèves. Écrivez un script qui effectue une copie triée de ce fichier.
  9. Écrivez un script permettant de trier une liste. Il ne pourra pas utiliser la méthode intégrée "sort()" de Python : vous devez donc définir vous-même l'algorithme de tri.

Solution

  1. Réfléchissez !
  2. Réfléchissez !
  3. # Affichage de tables de multiplication
    m, n = 3, 15
    chain =""
    for i in range(n):
        v = m * (i+1)               # calcul d'un des termes
        chain = chain + "%4d" % (v) # formatage à 4 caractères
    print(chain)
    
    3   6   9  12  15  18  21  24  27  30  33  36  39  42  45
    
  4. # Simple parcours d'une liste :
    lst = ['Jean-Michel', 'Marc', 'Vanessa', 'Anne',
           'Maximilien', 'Alexandre-Benoît', 'Louise']
    
    for e in lst:
        print("%s : %s caractères" % (e, len(e)))
    
  5. # Élimination de doublons
    
    lst = [9, 12, 40, 5, 12, 3, 27, 5, 9, 3, 8, 22, 40, 3, 2, 4, 6, 25]
    lst2 = []
    
    for el in lst:
        if el not in lst2:
            lst2.append(el)
    
    lst2.sort()
    print(lst2)
    
  6. Réfléchissez !
  7. # Afficher tous les jours d'une année :
    ## Cette variante utilise une liste de listes ##
    ## (que l'on pourrait aisément remplacer par deux listes distinctes)
    
    # La liste ci-dessous contient deux éléments qui sont eux-mêmes des listes.
    # l'élément 0 contient les nombres de jours de chaque mois, tandis que
    # l'élément 1 contient les noms des douze mois :
    mois = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
            ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet',
             'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']]
    
    jour = ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi']
    
    ja, jm, js, m = 0, 0, 0, 0
    
    while ja <365:
        ja, jm = ja +1, jm +1    # ja = jour dans l'année, jm = jour dans le mois
        js = (ja +3) % 7         # js = jour de la semaine. Le décalage ajouté 
                                 #      permet de choisir le jour de départ
      
        if jm > mois[0][m]:               # élément m de l'élément 0 de la liste
            jm, m = 1, m+1
    
        print jour[js], jm, mois[1][m]    # élément m de l'élément 1 de la liste
    
  8. Réfléchissez !
  9. Réfléchissez !


Tuples

Description d'un tuple

modifier

Vous devez vous rappeler une autre différence importante entre chaînes et listes : il n'est pas possible de changer les caractères au sein d'une chaîne existante, alors que vous pouvez modifier les éléments d'une liste. En d'autres termes, les listes sont des séquences modifiables, alors que les chaînes sont des séquences non-modifiables. Exemple :

>>> liste =['jambon','fromage','miel','confiture','chocolat']
>>> liste[1:3] =['salade']
>>> print liste
['jambon', 'salade', 'confiture', 'chocolat']
>>> chaine ='Roméo préfère Juliette'
>>> chaine[14:] ='Brigitte'
          ***** ==> Erreur: object doesn't support slice assignment  *****

Nous essayons de modifier la fin de la chaîne, mais cela ne marche pas. La seule possibilité d'arriver à nos fins est de créer une nouvelle chaîne et d'y recopier ce que nous voulons changer :

>>> chaine = chaine[:14] +'Brigitte'
>>> print chaine
Roméo préfère Brigitte

Python propose un type de données appelé tuple (anglicisme informatique signifiant "Table UPLEt"), qui est assez semblable à une liste mais qui n'est pas modifiable. Les tuples sont donc préférables aux listes partout où l'on veut être certain que les données transmises ne soient pas modifiées par erreur au sein d'un programme. En outre, les tuples sont moins « gourmands » en ressources système (ils occupent moins de place en mémoire).

Du point de vue de la syntaxe, un tuple est une collection d'éléments séparés par des virgules :

>>> tuple = 'a', 'b', 'c', 'd', 'e'
>>> print(tuple)
('a', 'b', 'c', 'd', 'e')

Pour améliorer la lisibilité du code, il est vivement conseillé de déclarer le tuple en évidence en l'enfermant dans une paire de parenthèses, comme l'instruction "print" de Python le fait elle-même.

>>> tuple = ('a', 'b', 'c', 'd', 'e')

Les opérations que l'on peut effectuer sur des tuples sont syntaxiquement similaires à celles que l'on effectue sur les listes, si ce n'est que les tuples ne sont pas modifiables :

>>> print(tuple[2:4])
('c', 'd')

>>> tuple[1:3] = ('x', 'y')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

>>> tuple = ('André',) + tuple[1:]	
>>> print(tuple)
('André', 'b', 'c', 'd', 'e')

Remarquez qu'il faut toujours au moins une virgule pour définir un tuple (le dernier exemple ci-dessus utilise un tuple contenant un seul élément : 'André').


Dictionnaires

Déclarations

modifier

Le dictionnaire ou tableau associatif n'est pas une séquence mais un autre type composite. Ils ressemblent aux listes dans une certaine mesure (ils sont modifiables comme elles), mais les éléments que nous allons y enregistrer ne seront pas disposés dans un ordre immuable. En revanche, nous pourrons accéder à n'importe lequel d'entre eux à l'aide d'un index spécifique que l'on appellera une clé, laquelle pourra être alphabétique, numérique, ou même d'un type composite sous certaines conditions.

 Comme dans une liste, les éléments mémorisés dans un dictionnaire peuvent être de n'importe quel type (valeurs numériques, chaînes, listes, etc.).

Création d'un dictionnaire

modifier

À titre d'exemple, nous allons créer un dictionnaire de langue, pour la traduction de termes informatiques anglais en français. Dans ce dictionnaire, les index seront des chaînes de caractères.

Puisque le type dictionnaire est un type modifiable, nous pouvons commencer par créer un dictionnaire vide, puis le remplir petit à petit. Du point de vue syntaxique, on reconnaît une structure de données de type dictionnaire au fait que ses éléments sont enfermés dans une paire d'accolades. Un dictionnaire vide sera donc noté { } :

dico = {}
dico['computer'] = 'ordinateur'
dico['mouse'] ='souris'
dico['keyboard'] ='clavier'
print dico
{'computer': 'ordinateur', 'keyboard': 'clavier', 'mouse': 'souris'}

Comme vous pouvez l'observer dans la ligne ci-dessus, un dictionnaire apparaît comme une série d'éléments séparés par des virgules (le tout étant enfermé entre deux accolades}. Chacun de ces éléments est constitué d'une paire d'objets : un index et une valeur, séparés par un double point.

Dans un dictionnaire, les index s'appellent des clés, et les éléments peuvent donc s'appeler des paires clé-valeur. Vous pouvez constater que l'ordre dans lequel les éléments apparaissent à la dernière ligne ne correspond pas à celui dans lequel nous les avons fournis. Cela n'a strictement aucune importance : nous n'essaierons jamais d'extraire une valeur d'un dictionnaire à l'aide d'un index numérique. Au lieu de cela, nous utiliserons les clés :

>>> print dico['mouse']
souris

Contrairement à ce qui se passe avec les listes, il n'est pas nécessaire de faire appel à une méthode particulière pour ajouter de nouveaux éléments à un dictionnaire : il suffit de créer une nouvelle paire clé-valeur.

Opérations sur les dictionnaires

modifier

Pour en enlever, vous utiliserez l'instruction del. Créons pour l'exemple un autre dictionnaire, destiné cette fois à contenir l'inventaire d'un stock de fruits. Les index (ou clés) seront les noms des fruits, et les valeurs seront les masses de ces fruits répertoriées dans le stock (il s'agit donc cette fois de valeurs de type numérique).

>>> invent = {'pommes': 430, 'bananes': 312, 'oranges' : 274, 'poires' : 137}
>>> print invent
{'oranges': 274, 'pommes': 430, 'bananes': 312, 'poires': 137}

Si le patron décide de liquider toutes les pommes et de ne plus en vendre, nous pouvons enlever cette entrée dans le dictionnaire :

>>> del invent['pommes']
>>> print invent
{'oranges': 274, 'bananes': 312, 'poires': 137}

La fonction len() est utilisable avec un dictionnaire : elle en renvoie le nombre d'éléments.

Les dictionnaires sont des objets

modifier

On peut appliquer aux dictionnaires un certain nombre de méthodes spécifiques :

keys et values

modifier

La méthode keys() renvoie la liste des clés utilisées dans le dictionnaire :

>>> print dico.keys()
['computer', 'keyboard', 'mouse']

La méthode values() renvoie la liste des valeurs mémorisées dans le dictionnaire :

>>> print invent.values()
[274, 312, 137]

has_key

modifier

La méthode has_key() permet de savoir si un dictionnaire comprend une clé déterminée. On fournit la clé en argument, et la méthode renvoie une valeur 'vraie' ou 'fausse' (en fait, 1 ou 0), suivant que la clé est présente ou pas :

 

Cette méthode ne fonctionne plus depuis Python 3.x, où il faut utiliser le nom de la clé in nom du dictionnaire.

>>> print invent.has_key('bananes')
1

>>> print 'bananes' in invent
1

>>> if invent.has_key('pommes'):
       print 'nous avons des pommes'
else:
       print 'pas de pommes, sorry'

pas de pommes, sorry

La méthode items() extrait du dictionnaire une liste équivalente de tuples :

>>> print invent.items()
[('oranges', 274), ('bananes', 312), ('poires', 137)]

Il est donc utilisé pour les "foreach" :

for key, value in invent.items():
    print "Clé : %s, valeur : %s." % (key, value)

La méthode copy() permet d'effectuer une vraie copie d'un dictionnaire. Il faut savoir en effet que la simple affectation d'un dictionnaire existant à une nouvelle variable crée seulement une nouvelle référence vers le même objet, et non un nouvel objet (aliasing). Par exemple, l'instruction ci-dessous ne définit pas un nouveau dictionnaire (contrairement aux apparences) :

>>> stock = invent
>>> print stock
{'oranges': 274, 'bananes': 312, 'poires': 137}

>>> del invent['bananes']
>>> print stock
{'oranges': 274, 'poires': 137}

Si nous modifions "invent", alors stock aussi est modifié, et vice-versa (ces deux noms désignent en effet le même objet dictionnaire dans la mémoire de l'ordinateur).

Pour obtenir une vraie copie (indépendante) d'un dictionnaire préexistant, il faut employer la méthode copy() :

>>> magasin = stock.copy()
>>> magasin['prunes'] = 561
>>> print magasin
{'oranges': 274, 'prunes': 561, 'poires': 137}
>>> print stock
{'oranges': 274, 'poires': 137}
>>> print invent
{'oranges': 274, 'poires': 137}

Il est possible de concaténer deux dictionnaires avec cette méthode :

>>> d = {'apples': 1, 'oranges': 3, 'pears': 2}
>>> ud = {'pears': 4, 'grapes': 5, 'lemons': 6}
>>> d.update(ud)
>>> d
{'grapes': 5, 'pears': 4, 'lemons': 6, 'apples': 1, 'oranges': 3}
>>>
 les doublons sont automatiquement fusionnés.

Pour trier un dictionnaire par clé :

d = sorted(d.items(), key=lambda x: x[0])

Pour trier par valeur :

d = sorted(d.items(), key=lambda x: x[1])

Pour l'inverse, ajouter : , reverse=True.

Parcours d'un dictionnaire

modifier

Vous pouvez utiliser une boucle for pour traiter successivement tous les éléments contenus dans un dictionnaire, mais attention :

  • Au cours de l'itération, ce sont les clés utilisées dans le dictionnaire qui seront successivement affectées à la variable de travail, et non les valeurs.
  • L'ordre dans lequel les éléments seront extraits est imprévisible (puisqu'un dictionnaire n'est pas une séquence).

Exemple :

>>> invent ={"oranges":274, "poires":137, "bananes":312}
>>> for clef in invent:
...    print clef
    
poires
bananes
oranges

Si vous souhaitez effectuer un traitement sur les valeurs, il vous suffit alors de récupérer chacune d'elles à partir de la clé correspondante :

for clef in invent:
    print clef, invent[clef]
    
poires 137
bananes 312
oranges 274

Cette manière de procéder n'est cependant pas idéale, ni en termes de performances ni même du point de vue de la lisibilité. Il est recommandé de plutôt faire appel à la méthode items() décrite à la section précédente :

for clef, valeur in invent.items():
    print clef, valeur
    
poires 137
bananes 312
oranges 274

Les clés ne sont pas nécessairement des chaînes de caractères

modifier

Jusqu'à présent nous avons décrit des dictionnaires dont les clés étaient à chaque fois des valeurs de type string. En fait nous pouvons utiliser en guise de clés n'importe quel type de donnée non modifiable : des entiers, des réels, des chaînes de caractères, et même des tuples.

Considérons par exemple que nous voulions répertorier les arbres remarquables situés dans un grand terrain rectangulaire. Nous pouvons pour cela utiliser un dictionnaire, dont les clés seront des tuples indiquant les coordonnées x,y de chaque arbre :

>>> arb = {}
>>> arb[(1,2)] = 'Peuplier'
>>> arb[(3,4)] = 'Platane'
>>> arb[6,5] = 'Palmier'
>>> arb[5,1] = 'Cycas'
>>> arb[7,3] = 'Sapin'

>>> print arb
{(3, 4): 'Platane', (6, 5): 'Palmier', (5, 1): 'Cycas', (1, 2): 'Peuplier', (7, 3): 'Sapin'}
>>> print arb[(6,5)]
palmier
 
foret disposée en grille dont les arbres sont générés par un dictionnaire

Vous pouvez remarquer que nous avons allégé l'écriture à partir de la troisième ligne, en profitant du fait que les parenthèses délimitant les tuples sont facultatives (à utiliser avec prudence !).

Dans ce genre de construction, il faut garder à l'esprit que le dictionnaire contient des éléments seulement pour certains couples de coordonnées. Ailleurs, il n'y a rien. Par conséquent, si nous voulons interroger le dictionnaire pour savoir ce qui se trouve là où il n'y a rien, comme par exemple aux coordonnées (2,1), nous allons provoquer une erreur :

>>> print arb[1,2]
Peuplier
>>> print arb[2,1]
                ***** Erreur : KeyError: (2, 1)  *****

Pour résoudre ce petit problème, nous pouvons utiliser la méthode get() :

>>> print arb.get((1,2),'néant')
Peuplier
>>> print arb.get((2,1),'néant')
néant

Le premier argument transmis à cette méthode est la clé de recherche, le second argument est la valeur que nous voulons obtenir en retour si la clé n'existe pas dans le dictionnaire.

Les dictionnaires ne sont pas des séquences

modifier

Comme vous l'avez vu plus haut, les éléments d'un dictionnaire ne sont pas disposés dans un ordre particulier. Des opérations comme la concaténation et l'extraction (d'un groupe d'éléments contigus) ne peuvent donc tout simplement pas s'appliquer ici. Si vous essayez tout de même, Python lèvera une erreur lors de l'exécution du code :

>>> print arb[1:3]
                ***** Erreur : KeyError: slice(1, 3, None) *****

Vous avez vu également qu'il suffit d'affecter un nouvel indice (une nouvelle clé) pour ajouter une entrée au dictionnaire. Cela ne marcherait pas avec les listes :

>>> invent['cerises'] = 987
>>> print invent
{'oranges': 274, 'cerises': 987, 'poires': 137}

>>> liste =['jambon', 'salade', 'confiture', 'chocolat']
>>> liste[4] ='salami'
          ***** IndexError: list assignment index out of range  *****

Du fait qu'ils ne sont pas des séquences, les dictionnaires se révèlent donc particulièrement précieux pour gérer des ensembles de données où l'on est amené à effectuer fréquemment des ajouts ou des suppressions, dans n'importe quel ordre. Ils remplacent avantageusement les listes lorsqu'il s'agit de traiter des ensembles de données numérotées, dont les numéros ne se suivent pas.

Exemple :

>>> client = {}
>>> client[4317] = "Dupond"
>>> client[256] = "Durand"
>>> client[782] = "Schmidt"

etc.

Exercices

  1. Écrivez un script qui crée un mini-système de base de données fonctionnant à l'aide d'un dictionnaire, et dans lequel vous mémoriserez les noms d'une série de copains, leur âge et leur taille. Votre script devra comporter deux fonctions : la première pour le remplissage du dictionnaire, et la seconde pour sa consultation. Dans la fonction de remplissage, utilisez une boucle pour accepter les données entrées par l'utilisateur. Dans le dictionnaire, le nom de l'élève servira de clé d'accès, et les valeurs seront constituées de tuples (âge, taille), dans lesquels l'âge sera exprimé en années (donnée de type entier), et la taille en mètres (donnée de type réel). La fonction de consultation comportera elle aussi une boucle, dans laquelle l'utilisateur pourra fournir un nom quelconque pour obtenir en retour le couple « âge, taille » correspondant. Le résultat de la requête devra être une ligne de texte bien formatée, telle par exemple : « Nom : Jean Dhoute - âge : 15 ans - taille : 1.74 m ».
  2. Écrivez une fonction qui échange les clés et les valeurs d'un dictionnaire (ce qui permettra par exemple de transformer un dictionnaire anglais/français en un dictionnaire français/anglais). (On suppose que le dictionnaire ne contient pas plusieurs valeurs identiques).

Solution

  1. #!/usr/bin/env python
    # coding: utf-8
    
    # Création du dictionnaire
    dico ={}
    while 1:
        choix = raw_input("Choisissez : (R)emplir - (C)onsulter - (T)erminer : ")
        if choix.upper() == 'T':
            break
    
        elif choix.upper() == 'R':
    	nom = raw_input("Entrez le nom (ou <enter> pour terminer) : ")
    	if nom == "":
    		break
    	age = int(raw_input("Entrez l'âge (nombre entier !) : "))
    	taille = float(raw_input("Entrez la taille (en mètres) : "))
    	dico[nom] = (age, taille)
    
        elif choix.upper() == 'C':
    	# Consultation
    	nom = raw_input("Entrez le nom (ou <enter> pour terminer) : ")
    	if nom == "":
    		break
    	if dico.has_key(nom):           # le nom est-il répertorié ?
    		item = dico[nom]            # consultation proprement dite
    		age, taille = item[0], item[1]
    		print "Nom : %s - âge : %s ans - taille : %s m."\
    			   % (nom, age, taille)          
    	else:
    		print "*** nom inconnu ! ***"
    
  2. # Échange des clés et des valeurs dans un dictionnaire
    dico = {'Computer':'Ordinateur',
            'Mouse':'Souris',
            'Keyboard':'Clavier',
            'Hard disk':'Disque dur',
            'Screen':'Ecran'}
    
    print(dico)
    
    dic_inv ={} 
    for cle in dico:
    	item = dico[cle]  
    	dic_inv[item] = cle
    
    print(dic_inv)
    

Construction d'un histogramme à l'aide d'un dictionnaire

modifier

Les dictionnaires constituent un outil très élégant pour construire des histogrammes.

Supposons par exemple que nous voulions établir l'histogramme qui représente la fréquence d'utilisation de chacune des lettres de l'alphabet dans un texte donné. L'algorithme permettant de réaliser ce travail est extraordinairement simple si on le construit sur base d'un dictionnaire :

>>> texte ="les saucisses et saucissons secs sont dans le saloir"
>>> lettres ={}
>>> for c in texte:
        lettres[c] = lettres.get(c, 0) + 1
	
>>> print lettres
{'t': 2, 'u': 2, 'r': 1, 's': 14, 'n': 3, 'o': 3, 'l': 3, 'i': 3, 'd': 1, 
'e': 5, 'c': 3, ' ': 8, 'a': 4}

Nous commençons par créer un dictionnaire vide : lettres. Ensuite, nous allons remplir ce dictionnaire en utilisant les caractères de l'alphabet en guise de clés. Les valeurs que nous mémoriserons pour chacune de ces clés seront les fréquences des caractères correspondants dans le texte. Afin de calculer celles-ci, nous effectuons un parcours de la chaîne de caractères texte. Pour chacun de ces caractères, nous interrogeons le dictionnaire à l'aide de la méthode get(), en utilisant le caractère en guise de clé, afin d'y lire la fréquence déjà mémorisée pour ce caractère. Si cette valeur n'existe pas encore, la méthode get() doit renvoyer une valeur nulle. Dans tous les cas, nous incrémentons la valeur trouvée, et nous la mémorisons dans le dictionnaire à l'emplacement qui correspond à la clé (c'est-à-dire au caractère en cours de traitement).

Pour fignoler notre travail, nous pouvons encore souhaiter afficher l'histogramme dans l'ordre alphabétique. Pour ce faire, nous pensons immédiatement à la méthode sort(), mais celle-ci ne peut s'appliquer qu'aux listes. Qu'à cela ne tienne ! Nous avons vu plus haut comment nous pouvions convertir un dictionnaire en une liste de tuples :

>>> lettres_triees = lettres.items()
>>> lettres_triees.sort()
>>> print lettres_triees
[(' ', 8), ('a', 4), ('c', 3), ('d', 1), ('e', 5), ('i', 3), ('l', 3), 
('n', 3), ('o', 3), ('r', 1), ('s', 14), ('t', 2), ('u', 2)]

Exercices

  1. Vous avez à votre disposition un fichier texte quelconque (pas trop gros). Écrivez un script qui compte les occurrences de chacune des lettres de l'alphabet dans ce texte (on ne tiendra pas compte du problème des lettres accentuées)..
  2. Modifiez le script ci-dessus afin qu'il établisse une table des occurrences de chaque mot dans le texte. Conseil : dans un texte quelconque, les mots ne sont pas seulement séparés par des espaces, mais également par divers signes de ponctuation. Pour simplifier le problème, vous pouvez commencer par remplacer tous les caractères non-alphabétiques par des espaces, et convertir la chaîne résultante en une liste de mots à l'aide de la méthode split().
  3. Vous avez à votre disposition un fichier texte quelconque (pas trop gros). Écrivez un script qui analyse ce texte, et mémorise dans un dictionnaire l'emplacement exact de chacun des mots (compté en nombre de caractères à partir du début). Lorsqu'un même mot apparaît plusieurs fois, tous ses emplacements doivent être mémorisés : chaque valeur de votre dictionnaire doit donc être une liste d'emplacements.

Solution

  1. # histogramme
    nFich = raw_input('Nom du fichier : ')
    fi = open(nFich, 'r')
    texte = fi.read()		# conversion du fichier en une chaîne de caractères
    fi.close()
    
    print texte
    dico ={}
    for c in texte:
        c = c.upper()		# conversion de toutes les lettres en majuscules
        dico[c] = dico.get(c, 0) +1
    
    liste = dico.items()
    liste.sort()
    print liste
    
  2. nFich = raw_input('Nom du fichier à traiter : ')
    fi = open(nFich, 'r')
    texte = fi.read()
    fi.close()
    
    # afin de pouvoir aisément séparer les mots du texte, on commence 
    # par convertir tous les caractères non-alphabétiques en espaces  :
    
    alpha = "abcdefghijklmnopqrstuvwxyzéèàùçâêîôûäëïöü"
    
    lettres = ''            # nouvelle chaîne à construire
    for c in texte:
        c = c.lower()       # conversion de chaque caractère en minuscule
        if c in alpha:
            lettres = lettres + c
        else:
            lettres = lettres + ' '
    
    # conversion de la chaîne résultante en une liste de mots :
    mots = lettres.split()
    
    
    # construction de l'histogramme :
    dico ={}
    for m in mots:
        dico[m] = dico.get(m, 0) +1
    
    liste = dico.items()
    
    # tri de la liste résultante :
    liste.sort()
    
    # affichage en clair :
    for item in liste:
        print item[0], ":", item[1]
    
  3. # encodage d'un texte dans un dictionnaire
    
    nFich = raw_input('Nom du fichier à traiter : ')
    fi = open(nFich, 'r')
    texte = fi.read()
    fi.close()
    
    # On considère que les mots sont des suites de caractères faisant partie
    # de la chaîne ci-dessous. Tous les autres sont des séparateurs :
    
    alpha = "abcdefghijklmnopqrstuvwxyzéèàùçâêîôûäëïöü"
    
    # construction du dictionnaire :
    dico ={}
    # parcours de tous les caractères du texte :
    i =0                    # indice du caractère en cours de lecture
    mot =""                 # variable de travail : mot en cours de lecture
    for c in texte:
        c = c.lower()       # conversion de chaque caractère en minuscule
        
        if c in alpha:      # car. alphab. => on est à l'intérieur d'un mot
            mot = mot + c   
        else:               # car. non-alphabétique => fin de mot
            if mot != "":   # afin d'ignorer les car. non-alphabétiques successifs
                # pour chaque mot, on construit une liste d'indices :
                if dico.has_key(mot):       # mot déjà répertorié :
                    dico[mot].append(i)     # ajout d'un indice à la liste
                else:                       # mot rencontré pour la 1e fois :
                    dico[mot] =[i]          # création de la liste d'indices
                mot =""     # préparer la lecture du mot suivant
        i = i+1             # indice du caractère suivant
          
    # Affichage du dictionnaire, en clair :
    for clef, valeur in dico.items():
        print clef, ":", valeur
    

Contrôle du flux d'exécution à l'aide d'un dictionnaire

modifier

Il arrive fréquemment que l'on ait à diriger l'exécution d'un programme dans différentes directions, en fonction de la valeur prise par une variable. Vous pouvez bien évidemment traiter ce problème à l'aide d'une série d'instructions if - elif - else , mais cela peut devenir assez lourd et inélégant si vous avez affaire à un grand nombre de possibilités. Exemple :

materiau = raw_input("Choisissez le matériau : ")

if materiau == 'fer':
    fonctionA()
elif materiau == 'bois':
    fonctionC()
elif materiau == 'cuivre':
    fonctionB()
elif materiau == 'pierre':
    fonctionD()
elif   ... etc ...

Les langages de programmation proposent souvent des instructions spécifiques pour traiter ce genre de problème, telles les instructions switch ou case du C ou du Pascal. Python n'en propose aucune, mais vous pouvez vous tirer d'affaire dans bien des cas à l'aide d'une liste, ou mieux encore à l'aide d'un dictionnaire. Exemple :

materiau = raw_input("Choisissez le matériau : ")

dico = {'fer':fonctionA,
        'bois':fonctionC,
        'cuivre':fonctionB,
        'pierre':fonctionD,
	    ... etc ...}
dico[materiau]()

Les deux instructions ci-dessus pourraient être condensées en une seule, mais nous les laissons séparées pour bien détailler le mécanisme :

  • La première instruction définit un dictionnaire dico dans lequel les clés sont les différentes possibilités pour la variable materiau, et les valeurs, les noms des fonctions à invoquer en correspondance. Notez bien qu'il s'agit seulement des noms de ces fonctions, qu'il ne faut surtout pas faire suivre de parenthèses dans ce cas (Sinon Python exécuterait chacune de ces fonctions au moment de la création du dictionnaire).
  • La seconde instruction invoque la fonction correspondant au choix opéré à l'aide de la variable materiau. Le nom de la fonction est extrait du dictionnaire à l'aide de la clé, puis associé à une paire de parenthèses. Python reconnaît alors un appel de fonction tout à fait classique et l'exécute.

Vous pouvez encore améliorer la technique ci-dessus en remplaçant cette instruction par sa variante ci-dessous, qui fait appel à la méthode get() afin de prévoir le cas où la clé demandée n'existerait pas dans le dictionnaire (vous obtenez de cette façon l'équivalent d'une instruction else terminant une longue série de elif) :

dico.get(materiau, fonctAutre)()

Lorsque la la valeur de la variable "materiau "ne correspond à aucune clé du dictionnaire, c'est la fonction fonctAutre() qui est invoquée.

Différences entre deux dictionnaires

modifier

Par exemple pour savoir quels sont les éléments importés[1] :

d1 = locals().copy()
import pywikibot
d2 = locals()
print(set(d2) - set(d1))

Références

modifier


Dates

Module datetime

modifier

Les dates se manipulent à l'aide du module datetime[1].

Syntaxe

modifier
>>> import datetime
>>> maDate = datetime.datetime.now()
>>> print (maDate)
2017-04-22 01:49:41.230711
>>>

Impossible de tronquer une date complète comme une chaine de caractères, il faut utiliser les fonctions du module :

>>> print (maDate.year)
2017
>>> print (maDate.month)
4
>>> print (maDate.day)
22
>>> print (maDate.hour)
1
>>> print (maDate.minute)
49
>>> print (maDate.second)
41
>>> print (maDate.microsecond)
230711
>>>

Les variables de ce type sont très faciles à additionner et soustraire :

>>> maDateDeFin = datetime.datetime.now()
>>> print (maDateDeFin - maDate)
0:04:38.266647

Références

modifier


Ensembles

Définition

modifier

En Python, les ensembles sont définis par le mot "set()"[1] depuis Python 2.3, d'abord en important le module du même nom, puis depuis nativement Python 2.6, avec "frozenset()".

Un ensemble est une collection non ordonnée d'objets, contrairement aux séquences comme les listes et les tuples dans lesquels chaque élément est indexé. Un ensemble ne peut pas contenir de doublon : on ne peut y trouver des éléments que zéro ou une fois. Tous les membres d'un ensemble doivent être hachable, comme les clés des dictionnaires. À titre d'exemple, les scalaires comme les entiers, flottants, tuples, et chaînes sont hachables ; par contre les dictionnaires, listes, et ensembles ne le sont pas.

Exemple :

set1 = set()                    # Nouvel ensemble vide
set1.add("cat")                 # Ajout d'un membre
set1.update(["dog", "mouse"])   # Ajout de plusieurs membres
if "cat" in set1:               # Recherche d'un membre
  set1.remove("cat")            # Retrait d'un membre
#set1.remove("elephant")        - Erreur de retrait d'un membre introuvable
set1.discard("elephant")        # Aucune erreur de retrait d'un membre introuvable

print(set1)                     # Affichage d'un ensemble
for item in set1:               # Itération pour chaque élément
  print(item)
print("Item count:", len(set1)) # Compte des éléments

#1stitem = set1[0]              # Erreur d'index introuvable
isempty = len(set1) == 0        # Test si l'ensemble est vide
set1 = set(["cat", "dog"])      # Initialisation de l'ensemble depuis une liste de membre
set2 = set(["dog", "mouse"])
set3 = set1 & set2              # Intersection
set4 = set1 | set2              # Union
set5 = set1 - set3              # Différence
set6 = set1 ^ set2              # Différence symétrique
issubset = set1 <= set2         # Test de sous-ensemble
issuperset = set1 >= set2       # Test de sur-ensemble
set7 = set1.copy()              # Copie d'un ensemble
set7.remove("cat")
set8 = set1.copy()
set8.clear()                    # Effacement d'un ensemble
print(set1, set2, set3, set4, set5, set6, set7, set8, issubset, issuperset)

Construction d'ensembles

modifier

Une première méthode consiste à fournir un objet séquentiel en paramètre :

>>> set([0, 1, 2, 3])
set([0, 1, 2, 3])

>>> set("obtuse")
set(['b', 'e', 'o', 's', 'u', 't'])

Ajout de chaque membre un par un :

>>> s = set([12, 26, 54])
>>> s.add(32)
>>> s
set([32, 26, 12, 54])

Ajout de groupes de membres :

>>> s.update([26, 12, 9, 14])
>>> s
set([32, 9, 12, 14, 54, 26])
 si on ajoute un doublon avec "add()" ou "update()", cela n'a aucun effet.

Ajout par copie d'un autre ensemble :

>>> s2 = s.copy()
>>> s2
set([32, 9, 12, 14, 54, 26])

Recherche de membre

modifier

Pour chercher si un élément existe dans un ensemble, on utilise "in" :

>>> 32 in s
True
>>> 6 in s
False
>>> 6 not in s
True

Si un sous-ensemble existe dans un ensemble, c'est "issubset()" :

>>> s.issubset(set([32, 8, 9, 12, 14, -4, 54, 26, 19]))
True

Si un sur-ensemble contient un ensemble, c'est "issuperset()" :

>>> s.issuperset(set([9, 12]))
True

# Équivalent à :
>>> s.issuperset([9, 12])

# Équivalent à :
>>> s >= [9, 12]

Retrait de membre

modifier

Il existe quatre fonctions pour retirer des membres à un ensemble :

  1. "pop" : retire un membre non précisé.
  2. "remove" : retire le membre existant précisé.
  3. "discard" : retire un membre précisé.
  4. "clear" : retire tous les éléments.
>>> s = set([1,2,3,4,5,6])
>>> s.pop()
1
>>> s
set([2,3,4,5,6])

>>> s.remove(3)
>>> s
set([2,4,5,6])

>>> s.remove(9)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
KeyError: 9

>>> s.clear()
>>> s
set([])

Itération des ensembles

modifier

Les éléments n'étant pas ordonnés, il n'y a qu'une boucle possible :

>>> s = set("blerg")
>>> for n in s:
...     print n,
...
r b e l g

Opérations sur les ensembles

modifier

Python offre les mêmes opérations sur les ensembles qu'en mathématiques, applicables par soit par des opérateurs, soit par des fonctions équivalentes. Les fonctions dont le nom se termine par _update modifie l'ensemble qui devient le résultat et ne retourne rien au lieu de retourner le résultat.

Intersection

modifier
 
L'intersection des deux cercles apparaît en rouge.

Les éléments communs à deux ensembles.

>>> s1 = set([4, 6, 9])
>>> s2 = set([1, 6, 8])
>>> s1.intersection(s2)
set([6])
>>> s1 & s2
set([6])

>>> s1.intersection_update(s2)
>>> s1
set([6])
 
L'union des deux cercles apparaît en rouge.

Somme des éléments de deux ensembles.

>>> s1 = set([4, 6, 9])
>>> s2 = set([1, 6, 8])
>>> s1.union(s2)
set([1, 4, 6, 8, 9])
>>> s1 | s2
set([1, 4, 6, 8, 9])

Différence symétrique

modifier
 
La différence symétrique des deux cercles apparaît en rouge.

Éléments contenu dans un seul ensemble à la fois, parmi deux. autrement  : [ l'union des deux #set] -[l'intersection]

>>> s1 = set([4, 6, 9])
>>> s2 = set([1, 6, 8])
>>> s1.symmetric_difference(s2)
set([8, 1, 4, 9])
>>> s1 ^ s2
set([8, 1, 4, 9])

>>> s1.symmetric_difference_update(s2)
>>> s1
set([8, 1, 4, 9])

Différence

modifier
 
La différence asymétrique entre les deux cercles apparaît en rouge.

Éléments non contenu dans un des deux ensembles.

>>> s1 = set([4, 6, 9])
>>> s2 = set([1, 6, 8])
>>> s1.difference(s2)
set([9, 4])
>>> s1 - s2
set([9, 4])

>>> s1.difference_update(s2)
>>> s1
set([9, 4])

Opérations non binaires

modifier

Depuis Python 2.6, les fonctions vues précédemment acceptent plus de deux arguments :

  1. .intersection()
  2. .union()
  3. .symmetric_difference()
  4. .difference().

Un appel à plus de deux arguments est équivalent à des appels enchaînés à deux arguments, ou un argument dans le cas d'un appel de méthode sur une instance.

Exemple :

>>> s1 = set([3, 6, 7, 9])
>>> s2 = set([6, 7, 9, 10])
>>> s3 = set([7, 9, 10, 11])
>>> set.intersection(s1, s2, s3)
set([9, 7])
>>> set.intersection(s1, s2).intersection(s3)
set([9, 7])
>>> s1.intersection(s2).intersection(s3)
set([9, 7])
>>> s1.intersection(s2,s3)
set([9, 7])

frozenset

modifier

Un "frozenset" (ensemble figé) se comporte comme un ensemble, sauf qu'il est immutable, c'est-à-dire qu'une fois créé, on ne peut pas le mettre à jour. Il dispose donc des mêmes fonctions que le type "set", mais sans "add", "update", "pop", "remove", "discard" et "clear".

De plus, ils sont hachables, ce qui leur permet de faire partie d'ensembles.

>>> fs = frozenset([2, 3, 4])
>>> s1 = set([fs, 4, 5, 6])
>>> s1
set([4, frozenset([2, 3, 4]), 6, 5])
>>> fs.intersection(s1)
frozenset([4])

>>> fs.add(6)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'frozenset' object has no attribute 'add'

Les instructions suivantes montrent que les méthodes modificatrices sont absentes de la classe frozenset :

>>> set(dir(set)) - set(dir(frozenset))
{'__iand__', 'pop', 'add', '__isub__', 'clear', '__ior__', 'discard', 'update', '__ixor__', 'intersection_update', 'difference_update', 'symmetric_difference_update', 'remove'}
>>> set(dir(frozenset)) - set(dir(set))
set()

Exercices

modifier
  1. Créer un set {'cat', 1, 2, 3}, appelé "s".
  2. Créer un set {'c', 'a', 't', '1', '2', '3'}.
  3. Créer un frozen set {'cat', 1, 2, 3}, appelé "fs".
  4. Créer un set contenant {frozenset({'cat', 2, 3, 1})}.

Références

modifier
  GFDL Vous avez la permission de copier, distribuer et/ou modifier ce document selon les termes de la licence de documentation libre GNU, version 1.2 ou plus récente publiée par la Free Software Foundation ; sans sections inaltérables, sans texte de première page de couverture et sans texte de dernière page de couverture.