# 5. Structures de données

Ce chapitre reprend plus en détail quelques points déjà décrits précédemment et introduit également de nouvelles notions.

## 5.1. Compléments sur les listes

Le type liste dispose de méthodes supplémentaires. Voici toutes les méthodes des objets de type liste :

`list.``append`(x)

  Ajoute un élément à la fin de la liste. Équivalent à `a[len(a):] = [x]`.

`list.``extend`(iterable)

  Étend la liste en y ajoutant tous les éléments de l'itérable. Équivalent à `a[len(a):] = iterable`.

`list.``insert`(i, x)

  Insère un élément à la position indiquée. Le premier argument est la position de l'élément courant avant lequel l'insertion doit s'effectuer, donc `a.insert(0, x)` insère l'élément en tête de la liste et `a.insert(len(a), x)` est équivalent à `a.append(x)`.

`list.``remove`(x)

  Supprime de la liste le premier élément dont la valeur est égale à x. Une exception `ValueError` est levée s'il n'existe aucun élément avec cette valeur.

`list.``pop`([i])

  Enlève de la liste l'élément situé à la position indiquée et le renvoie en valeur de retour. Si aucune position n'est spécifiée, `a.pop()` enlève et renvoie le dernier élément de la liste (les crochets autour du i dans la signature de la méthode indiquent que ce paramètre est facultatif et non que vous devez placer des crochets dans votre code ! Vous retrouverez cette notation fréquemment dans le Guide de Référence de la Bibliothèque Python).

`list.``clear`()

  Supprime tous les éléments de la liste. Équivalent à `del a[:]`.

`list.``index`(x[, start[, end]])

  Renvoie la position du premier élément de la liste dont la valeur égale x (en commençant à compter les positions à partir de zéro). Une exception `ValueError` est levée si aucun élément n'est trouvé.

  Les arguments optionnels start et end sont interprétés de la même manière que dans la notation des tranches et sont utilisés pour limiter la recherche à une sous-séquence particulière. L'indice renvoyé est calculé relativement au début de la séquence complète et non relativement à start.

`list.``count`(x)

  Renvoie le nombre d'éléments ayant la valeur x dans la liste.

`list.``sort`(*, key=None, reverse=False)

  Ordonne les éléments dans la liste (les arguments peuvent personnaliser l'ordonnancement, voir `sorted()` pour leur explication).

`list.``reverse`()

  Inverse l'ordre des éléments dans la liste.

`list.``copy`()

  Renvoie une copie superficielle de la liste. Équivalent à `a[:]`.

L'exemple suivant utilise la plupart des méthodes des listes :

    >>> fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
    >>> fruits.count('apple')
    2
    >>> fruits.count('tangerine')
    0
    >>> fruits.index('banana')
    3
    >>> fruits.index('banana', 4)  # Find next banana starting a position 4
    6
    >>> fruits.reverse()
    >>> fruits
    ['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange']
    >>> fruits.append('grape')
    >>> fruits
    ['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange', 'grape']
    >>> fruits.sort()
    >>> fruits
    ['apple', 'apple', 'banana', 'banana', 'grape', 'kiwi', 'orange', 'pear']
    >>> fruits.pop()
    'pear'

Vous avez probablement remarqué que les méthodes telles que `insert`, `remove` ou `sort`, qui ne font que modifier la liste, n'affichent pas de valeur de retour (elles renvoient `None`) 1. C'est un principe respecté par toutes les structures de données variables en Python.

Une autre chose que vous remarquerez peut-être est que toutes les données ne peuvent pas être ordonnées ou comparées. Par exemple, `[None, 'hello', 10]` ne sera pas ordonné parce que les entiers ne peuvent pas être comparés aux chaînes de caractères et None ne peut pas être comparé à d'autres types. En outre, il existe certains types qui n'ont pas de relation d'ordre définie. Par exemple, `3+4j < 5+7j` n'est pas une comparaison valide.

### 5.1.1. Utilisation des listes comme des piles

Les méthodes des listes rendent très facile leur utilisation comme des piles, où le dernier élément ajouté est le premier récupéré (« dernier entré, premier sorti » ou LIFO pour last-in, first-out en anglais). Pour ajouter un élément sur la pile, utilisez la méthode `append()`. Pour récupérer l'objet au sommet de la pile, utilisez la méthode `pop()` sans indicateur de position. Par exemple :

    >>> stack = [3, 4, 5]
    >>> stack.append(6)
    >>> stack.append(7)
    >>> stack
    [3, 4, 5, 6, 7]
    >>> stack.pop()
    7
    >>> stack
    [3, 4, 5, 6]
    >>> stack.pop()
    6
    >>> stack.pop()
    5
    >>> stack
    [3, 4]

### 5.1.2. Utilisation des listes comme des files

Il est également possible d'utiliser une liste comme une file, où le premier élément ajouté est le premier récupéré (« premier entré, premier sorti » ou FIFO pour first-in, first-out) ; toutefois, les listes ne sont pas très efficaces pour réaliser ce type de traitement. Alors que les ajouts et suppressions en fin de liste sont rapides, les opérations d'insertions ou de retraits en début de liste sont lentes (car tous les autres éléments doivent être décalés d'une position).

Pour implémenter une file, utilisez la classe `collections.deque` qui a été conçue pour réaliser rapidement les opérations d'ajouts et de retraits aux deux extrémités. Par exemple :

    >>> from collections import deque
    >>> queue = deque(["Eric", "John", "Michael"])
    >>> queue.append("Terry")           # Terry arrives
    >>> queue.append("Graham")          # Graham arrives
    >>> queue.popleft()                 # The first to arrive now leaves
    'Eric'
    >>> queue.popleft()                 # The second to arrive now leaves
    'John'
    >>> queue                           # Remaining queue in order of arrival
    deque(['Michael', 'Terry', 'Graham'])

### 5.1.3. Compréhensions de listes

Les compréhensions de listes fournissent un moyen de construire des listes de manière très concise. Une application classique est la construction de nouvelles listes où chaque élément est le résultat d'une opération appliquée à chaque élément d'une autre séquence ; ou de créer une sous-séquence des éléments satisfaisant une condition spécifique.

Par exemple, supposons que l'on veuille créer une liste de carrés, comme :

    >>> squares = []
    >>> for x in range(10):
    ...     squares.append(x**2)
    ...
    >>> squares
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Notez que cela crée (ou remplace) une variable nommée `x` qui existe toujours après l'exécution de la boucle. On peut calculer une liste de carrés sans effet de bord avec :

    squares = list(map(lambda x: x**2, range(10)))

ou, de manière équivalente :

    squares = [x**2 for x in range(10)]

qui est plus court et lisible.

Une compréhension de liste consiste à placer entre crochets une expression suivie par une clause `for` puis par zéro ou plus clauses `for` ou `if`. Le résultat est une nouvelle liste résultat de l'évaluation de l'expression dans le contexte des clauses `for` et `if` qui la suivent. Par exemple, cette compréhension de liste combine les éléments de deux listes s'ils ne sont pas égaux :

    >>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
    [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

et c'est équivalent à :

    >>> combs = []
    >>> for x in [1,2,3]:
    ...     for y in [3,1,4]:
    ...         if x != y:
    ...             combs.append((x, y))
    ...
    >>> combs
    [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

Notez que l'ordre des instructions `for` et `if` est le même dans ces différents extraits de code.

Si l'expression est un n-uplet (c'est-à-dire `(x, y)` dans cet exemple), elle doit être entourée par des parenthèses :

    >>> vec = [-4, -2, 0, 2, 4]
    >>> # create a new list with the values doubled
    >>> [x*2 for x in vec]
    [-8, -4, 0, 4, 8]
    >>> # filter the list to exclude negative numbers
    >>> [x for x in vec if x >= 0]
    [0, 2, 4]
    >>> # apply a function to all the elements
    >>> [abs(x) for x in vec]
    [4, 2, 0, 2, 4]
    >>> # call a method on each element
    >>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
    >>> [weapon.strip() for weapon in freshfruit]
    ['banana', 'loganberry', 'passion fruit']
    >>> # create a list of 2-tuples like (number, square)
    >>> [(x, x**2) for x in range(6)]
    [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
    >>> # the tuple must be parenthesized, otherwise an error is raised
    >>> [x, x**2 for x in range(6)]
      File "<stdin>", line 1, in <module>
        [x, x**2 for x in range(6)]
                   ^
    SyntaxError: invalid syntax
    >>> # flatten a list using a listcomp with two 'for'
    >>> vec = [[1,2,3], [4,5,6], [7,8,9]]
    >>> [num for elem in vec for num in elem]
    [1, 2, 3, 4, 5, 6, 7, 8, 9]

Les compréhensions de listes peuvent contenir des expressions complexes et des fonctions imbriquées :

    >>> from math import pi
    >>> [str(round(pi, i)) for i in range(1, 6)]
    ['3.1', '3.14', '3.142', '3.1416', '3.14159']

### 5.1.4. Compréhensions de listes imbriquées

La première expression dans une compréhension de liste peut être n'importe quelle expression, y compris une autre compréhension de liste.

Voyez l'exemple suivant d'une matrice de 3 par 4, implémentée sous la forme de 3 listes de 4 éléments :

    >>> matrix = [
    ...     [1, 2, 3, 4],
    ...     [5, 6, 7, 8],
    ...     [9, 10, 11, 12],
    ... ]

Cette compréhension de liste transpose les lignes et les colonnes :

    >>> [[row[i] for row in matrix] for i in range(4)]
    [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

Comme nous l'avons vu dans la section précédente, la compréhension de liste imbriquée est évaluée dans le contexte de l'instruction `for` qui la suit, donc cet exemple est équivalent à :

    >>> transposed = []
    >>> for i in range(4):
    ...     transposed.append([row[i] for row in matrix])
    ...
    >>> transposed
    [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

lequel à son tour est équivalent à :

    >>> transposed = []
    >>> for i in range(4):
    ...     # the following 3 lines implement the nested listcomp
    ...     transposed_row = []
    ...     for row in matrix:
    ...         transposed_row.append(row[i])
    ...     transposed.append(transposed_row)
    ...
    >>> transposed
    [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

Dans des cas concrets, il est toujours préférable d'utiliser des fonctions natives plutôt que des instructions de contrôle de flux complexes. La fonction `zip()` ferait dans ce cas un excellent travail :

    >>> list(zip(*matrix))
    [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

Voyez Séparation des listes d'arguments pour plus de détails sur l'astérisque de cette ligne.

## 5.2. L'instruction `del`

Il existe un moyen de retirer un élément d'une liste à partir de sa position au lieu de sa valeur : l'instruction `del`. Elle diffère de la méthode `pop()` qui, elle, renvoie une valeur. L'instruction `del` peut également être utilisée pour supprimer des tranches d'une liste ou la vider complètement (ce que nous avions fait auparavant en affectant une liste vide à la tranche). Par exemple :

    >>> a = [-1, 1, 66.25, 333, 333, 1234.5]
    >>> del a[0]
    >>> a
    [1, 66.25, 333, 333, 1234.5]
    >>> del a[2:4]
    >>> a
    [1, 66.25, 1234.5]
    >>> del a[:]
    >>> a
    []

`del` peut aussi être utilisée pour supprimer des variables :

    >>> del a

À partir de là, référencer le nom `a` est une erreur (au moins jusqu'à ce qu'une autre valeur lui soit affectée). Vous trouverez d'autres utilisations de la fonction `del` plus tard.

## 5.3. Tuples et séquences

Nous avons vu que les listes et les chaînes de caractères ont beaucoup de propriétés en commun, comme l'indiçage et les opérations sur des tranches. Ce sont deux exemples de séquences (voir Types séquentiels — list, tuple, range). Comme Python est un langage en constante évolution, d'autres types de séquences y seront peut-être ajoutés. Il existe également un autre type standard de séquence : le tuple (ou n-uplet, dénomination que nous utiliserons dans la suite de cette documentation).

Un n-uplet consiste en différentes valeurs séparées par des virgules, par exemple :

    >>> t = 12345, 54321, 'hello!'
    >>> t[0]
    12345
    >>> t
    (12345, 54321, 'hello!')
    >>> # Tuples may be nested:
    ... u = t, (1, 2, 3, 4, 5)
    >>> u
    ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
    >>> # Tuples are immutable:
    ... t[0] = 88888
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'tuple' object does not support item assignment
    >>> # but they can contain mutable objects:
    ... v = ([1, 2, 3], [3, 2, 1])
    >>> v
    ([1, 2, 3], [3, 2, 1])

Comme vous pouvez le voir, les n-uplets sont toujours affichés entre parenthèses, de façon à ce que des n-uplets imbriqués soient interprétés correctement ; ils peuvent être saisis avec ou sans parenthèses, même si celles-ci sont souvent nécessaires (notamment lorsqu'un n-uplet fait partie d'une expression plus longue). Il n'est pas possible d'affecter de valeur à un élément d'un n-uplet ; par contre, il est possible de créer des n-uplets contenant des objets muables, comme des listes.

Si les n-uplets peuvent sembler similaires aux listes, ils sont souvent utilisés dans des cas différents et pour des raisons différentes. Les n-uplets sont immuables et contiennent souvent des séquences hétérogènes d'éléments qui sont accédés par « dissociation » (unpacking en anglais, voir plus loin) ou par indice (ou même par attributs dans le cas des `namedtuples`). Les listes sont souvent muables et contiennent des éléments généralement homogènes qui sont accédés par itération sur la liste.

Un problème spécifique est la construction de n-uplets ne contenant aucun ou un seul élément : la syntaxe a quelques tournures spécifiques pour s'en accommoder. Les n-uplets vides sont construits par une paire de parenthèses vides ; un n-uplet avec un seul élément est construit en faisant suivre la valeur par une virgule (il n'est pas suffisant de placer cette valeur entre parenthèses). Pas très joli, mais efficace. Par exemple :

    >>> empty = ()
    >>> singleton = 'hello',    # <-- note trailing comma
    >>> len(empty)
    0
    >>> len(singleton)
    1
    >>> singleton
    ('hello',)

L'instruction `t = 12345, 54321, 'hello !'` est un exemple d'un d'agrégation de *n-uplet* (tuple packing en anglais) : les valeurs `12345`, `54321` et `hello !` sont agrégées ensemble dans un n-uplet. L'opération inverse est aussi possible :

    >>> x, y, z = t

Ceci est appelé, de façon plus ou moins appropriée, un dissociation de séquence (sequence unpacking en anglais) et fonctionne pour toute séquence placée à droite de l'expression. Cette dissociation requiert autant de variables dans la partie gauche qu'il y a d'éléments dans la séquence. Notez également que cette affectation multiple est juste une combinaison entre une agrégation de n-uplet et une dissociation de séquence.

## 5.4. Ensembles

Python fournit également un type de donnée pour les ensembles. Un ensemble est une collection non ordonnée sans élément dupliqué. Des utilisations basiques concernent par exemple des tests d'appartenance ou des suppressions de doublons. Les ensembles savent également effectuer les opérations mathématiques telles que les unions, intersections, différences et différences symétriques.

Des accolades ou la fonction `set()` peuvent être utilisés pour créer des ensembles. Notez que pour créer un ensemble vide, `{}` ne fonctionne pas, cela crée un dictionnaire vide. Utilisez plutôt `set()`.

Voici une brève démonstration :

    >>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
    >>> print(basket)                      # show that duplicates have been removed
    {'orange', 'banana', 'pear', 'apple'}
    >>> 'orange' in basket                 # fast membership testing
    True
    >>> 'crabgrass' in basket
    False

    >>> # Demonstrate set operations on unique letters from two words
    ...
    >>> a = set('abracadabra')
    >>> b = set('alacazam')
    >>> a                                  # unique letters in a
    {'a', 'r', 'b', 'c', 'd'}
    >>> a - b                              # letters in a but not in b
    {'r', 'd', 'b'}
    >>> a | b                              # letters in a or b or both
    {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
    >>> a & b                              # letters in both a and b
    {'a', 'c'}
    >>> a ^ b                              # letters in a or b but not both
    {'r', 'd', 'b', 'm', 'z', 'l'}

Tout comme pour les compréhensions de listes, il est possible d'écrire des compréhensions d'ensembles :

    >>> a = {x for x in 'abracadabra' if x not in 'abc'}
    >>> a
    {'r', 'd'}

## 5.5. Dictionnaires

Un autre type de donnée très utile, natif dans Python, est le dictionnaire (voir Les types de correspondances — dict). Ces dictionnaires sont parfois présents dans d'autres langages sous le nom de « mémoires associatives » ou de « tableaux associatifs ». À la différence des séquences, qui sont indexées par des nombres, les dictionnaires sont indexés par des clés, qui peuvent être de n'importe quel type immuable ; les chaînes de caractères et les nombres peuvent toujours être des clés. Des n-uplets peuvent être utilisés comme clés s'ils ne contiennent que des chaînes, des nombres ou des n-uplets ; si un n-uplet contient un objet muable, de façon directe ou indirecte, il ne peut pas être utilisé comme une clé. Vous ne pouvez pas utiliser des listes comme clés, car les listes peuvent être modifiées en place en utilisant des affectations par position, par tranches ou via des méthodes comme `append()` ou `extend()`.

Le plus simple est de considérer les dictionnaires comme des ensembles de paires clé: valeur, les clés devant être uniques (au sein d'un dictionnaire). Une paire d'accolades crée un dictionnaire vide : `{}`. Placer une liste de paires clé:valeur séparées par des virgules à l'intérieur des accolades ajoute les valeurs correspondantes au dictionnaire ; c'est également de cette façon que les dictionnaires sont affichés.

Les opérations classiques sur un dictionnaire consistent à stocker une valeur pour une clé et à extraire la valeur correspondant à une clé. Il est également possible de supprimer une paire clé-valeur avec `del`. Si vous stockez une valeur pour une clé qui est déjà utilisée, l'ancienne valeur associée à cette clé est perdue. Si vous tentez d'extraire une valeur associée à une clé qui n'existe pas, une exception est levée.

Exécuter `list(d)` sur un dictionnaire `d` renvoie une liste de toutes les clés utilisées dans le dictionnaire, dans l'ordre d'insertion (si vous voulez qu'elles soient ordonnées, utilisez `sorted(d)`). Pour tester si une clé est dans le dictionnaire, utilisez le mot-clé `in`.

Voici un petit exemple utilisant un dictionnaire :

    >>> tel = {'jack': 4098, 'sape': 4139}
    >>> tel['guido'] = 4127
    >>> tel
    {'jack': 4098, 'sape': 4139, 'guido': 4127}
    >>> tel['jack']
    4098
    >>> del tel['sape']
    >>> tel['irv'] = 4127
    >>> tel
    {'jack': 4098, 'guido': 4127, 'irv': 4127}
    >>> list(tel)
    ['jack', 'guido', 'irv']
    >>> sorted(tel)
    ['guido', 'irv', 'jack']
    >>> 'guido' in tel
    True
    >>> 'jack' not in tel
    False

Le constructeur `dict()` fabrique un dictionnaire directement à partir d'une liste de paires clé-valeur stockées sous la forme de n-uplets :

    >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
    {'sape': 4139, 'guido': 4127, 'jack': 4098}

De plus, il est possible de créer des dictionnaires par compréhension depuis un jeu de clef et valeurs :

    >>> {x: x**2 for x in (2, 4, 6)}
    {2: 4, 4: 16, 6: 36}

Lorsque les clés sont de simples chaînes de caractères, il est parfois plus facile de spécifier les paires en utilisant des paramètres nommés :

    >>> dict(sape=4139, guido=4127, jack=4098)
    {'sape': 4139, 'guido': 4127, 'jack': 4098}

## 5.6. Techniques de boucles

Lorsque vous faites une boucle sur un dictionnaire, les clés et leurs valeurs peuvent être récupérées en même temps en utilisant la méthode `items()` :

    >>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
    >>> for k, v in knights.items():
    ...     print(k, v)
    ...
    gallahad the pure
    robin the brave

Lorsque vous faites une boucle sur une séquence, la position et la valeur correspondante peuvent être récupérées en même temps en utilisant la fonction `enumerate()`.

    >>> for i, v in enumerate(['tic', 'tac', 'toe']):
    ...     print(i, v)
    ...
    0 tic
    1 tac
    2 toe

Pour faire une boucle sur deux séquences ou plus en même temps, les éléments peuvent associés en utilisant la fonction `zip()` :

    >>> questions = ['name', 'quest', 'favorite color']
    >>> answers = ['lancelot', 'the holy grail', 'blue']
    >>> for q, a in zip(questions, answers):
    ...     print('What is your {0}?  It is {1}.'.format(q, a))
    ...
    What is your name?  It is lancelot.
    What is your quest?  It is the holy grail.
    What is your favorite color?  It is blue.

Pour faire une boucle en sens inverse sur une séquence, commencez par spécifier la séquence dans son ordre normal, puis appliquez la fonction `reversed()` :

    >>> for i in reversed(range(1, 10, 2)):
    ...     print(i)
    ...
    9
    7
    5
    3
    1

Pour faire une boucle sur une séquence de manière ordonnée, utilisez la fonction `sorted()` qui renvoie une nouvelle liste ordonnée sans altérer la source :

    >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
    >>> for i in sorted(basket):
    ...     print(i)
    ...
    apple
    apple
    banana
    orange
    orange
    pear

L'utilisation de la fonction `set()` sur une séquence élimine les doublons. L'utilisation de la fonction `sorted()` en combinaison avec `set()` sur une séquence est une façon idiomatique de boucler sur les éléments uniques d'une séquence dans l'ordre. :

    >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
    >>> for f in sorted(set(basket)):
    ...     print(f)
    ...
    apple
    banana
    orange
    pear

Il est parfois tentant de modifier une liste pendant son itération. Cependant, c'est souvent plus simple et plus sûr de créer une nouvelle liste à la place. :

    >>> import math
    >>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
    >>> filtered_data = []
    >>> for value in raw_data:
    ...     if not math.isnan(value):
    ...         filtered_data.append(value)
    ...
    >>> filtered_data
    [56.2, 51.7, 55.3, 52.5, 47.8]

## 5.7. Plus d'informations sur les conditions

Les conditions utilisées dans une instruction `while` ou `if` peuvent contenir n'importe quel opérateur, pas seulement des comparaisons.

The comparison operators `in` and `not in` check whether a value occurs (does not occur) in a sequence. The operators `is` and `is not` compare whether two objects are really the same object. All comparison operators have the same priority, which is lower than that of all numerical operators.

Les comparaisons peuvent être enchaînées. Par exemple, `a < b == c` teste si `a` est inférieur à `b` et si, de plus, `b` égale `c`.

Les comparaisons peuvent être combinées en utilisant les opérateurs booléens `and` et `or`, le résultat d'une comparaison (ou de toute expression booléenne) pouvant être inversé avec `not`. Ces opérateurs ont une priorité inférieure à celle des opérateurs de comparaison ; entre eux, `not` a la priorité la plus élevée et `or` la plus faible, de telle sorte que `A and not B or C` est équivalent à `(A and (not B)) or C`. Comme toujours, des parenthèses peuvent être utilisées pour exprimer l'instruction désirée.

Les opérateurs booléens `and` et `or` sont appelés opérateurs en circuit court : leurs arguments sont évalués de la gauche vers la droite et l'évaluation s'arrête dès que le résultat est déterminé. Par exemple, si `A` et `C` sont vrais et `B` est faux, `A and B and C` n'évalue pas l'expression `C`. Lorsqu'elle est utilisée en tant que valeur et non en tant que booléen, la valeur de retour d'un opérateur en circuit court est celle du dernier argument évalué.

Il est possible d'affecter le résultat d'une comparaison ou d'une autre expression booléenne à une variable. Par exemple :

    >>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
    >>> non_null = string1 or string2 or string3
    >>> non_null
    'Trondheim'

Notez qu'en Python, à la différence du C, une affectation à l'intérieur d'une expression doit être faite explicitement avec l'opérateur morse `:=`. Cela évite des erreurs fréquentes que l'on rencontre en C, lorsque l'on tape `=` alors que l'on voulait faire un test avec `==`.

## 5.8. Comparer des séquences avec d'autres types

Des séquences peuvent être comparées avec d'autres séquences du même type. La comparaison utilise un ordre lexicographique : les deux premiers éléments de chaque séquence sont comparés et, s'ils diffèrent, cela détermine le résultat de la comparaison ; s'ils sont égaux, les deux éléments suivants sont comparés à leur tour et ainsi de suite jusqu'à ce que l'une des séquences soit épuisée. Si deux éléments à comparer sont eux-mêmes des séquences du même type, alors la comparaison lexicographique est effectuée récursivement. Si tous les éléments des deux séquences sont égaux, les deux séquences sont alors considérées comme égales. Si une séquence est une sous-séquence de l'autre, la séquence la plus courte est celle dont la valeur est inférieure. La comparaison lexicographique des chaînes de caractères utilise le code Unicode des caractères. Voici quelques exemples de comparaisons entre séquences de même type :

    (1, 2, 3)              < (1, 2, 4)
    [1, 2, 3]              < [1, 2, 4]
    'ABC' < 'C' < 'Pascal' < 'Python'
    (1, 2, 3, 4)           < (1, 2, 4)
    (1, 2)                 < (1, 2, -1)
    (1, 2, 3)             == (1.0, 2.0, 3.0)
    (1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)

Comparer des objets de type différents avec `<` ou `>` est autorisé si les objets ont des méthodes de comparaison appropriées. Par exemple, les types numériques sont comparés via leur valeur numérique, donc 0 égale 0,0, etc. Dans les autres cas, au lieu de donner un ordre imprévisible, l'interpréteur lève une exception `TypeError`.

Notes

1

  D'autres langages renvoient l'objet modifié, ce qui permet de chaîner les méthodes comme ceci : `d->insert("a")->remove("b")->sort();`.