Fondamentals des séquences Python

PythonPythonBeginner
Pratiquer maintenant

This tutorial is from open-source community. Access the source code

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Les séquences Python sont des collections ordonnées d'éléments. Elles sont indexées par des entiers.

Types de données séquence

Python dispose de trois types de données séquence.

  • Chaîne de caractères : 'Hello'. Une chaîne de caractères est une séquence de caractères.
  • Liste : [1, 4, 5].
  • Tuple : ('GOOG', 100, 490.1).

Toutes les séquences sont ordonnées, indexées par des entiers et ont une longueur.

a = 'Hello'               ## Chaîne de caractères
b = [1, 4, 5]             ## Liste
c = ('GOOG', 100, 490.1)  ## Tuple

## Ordre d'indexation
a[0]                      ## 'H'
b[-1]                     ## 5
c[1]                      ## 100

## Longueur de la séquence
len(a)                    ## 5
len(b)                    ## 3
len(c)                    ## 3

Les séquences peuvent être replicées : s * n.

>>> a = 'Hello'
>>> a * 3
'HelloHelloHello'
>>> b = [1, 2, 3]
>>> b * 2
[1, 2, 3, 1, 2, 3]
>>>

Les séquences du même type peuvent être concaténées : s + t.

>>> a = (1, 2, 3)
>>> b = (4, 5)
>>> a + b
(1, 2, 3, 4, 5)
>>>
>>> c = [1, 5]
>>> a + c
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate tuple (not "list") to tuple

Extraction de segments

L'extraction de segments consiste à extraire une sous-séquence d'une séquence. La syntaxe est s[start:end]. start et end sont les index de la sous-séquence que vous souhaitez.

a = [0,1,2,3,4,5,6,7,8]

a[2:5]    ## [2,3,4]
a[-5:]    ## [4,5,6,7,8]
a[:3]     ## [0,1,2]
  • Les index start et end doivent être des entiers.
  • Les extractions de segments n'incluent pas la valeur de fin. C'est comme un intervalle demi-ouvert en mathématiques.
  • Si les index sont omis, ils prennent la valeur par défaut du début ou de la fin de la liste.

Réaffectation des segments

Sur les listes, les segments peuvent être réaffectés et supprimés.

## Réaffectation
a = [0,1,2,3,4,5,6,7,8]
a[2:4] = [10,11,12]       ## [0,1,10,11,12,4,5,6,7,8]

Nota : Le segment réaffecté n'a pas besoin d'avoir la même longueur.

## Suppression
a = [0,1,2,3,4,5,6,7,8]
del a[2:4]                ## [0,1,4,5,6,7,8]

Réductions de séquence

Il existe quelques fonctions communes pour réduire une séquence à une seule valeur.

>>> s = [1, 2, 3, 4]
>>> sum(s)
10
>>> min(s)
1
>>> max(s)
4
>>> t = ['Hello', 'World']
>>> max(t)
'World'
>>>

Itération sur une séquence

La boucle for itère sur les éléments d'une séquence.

>>> s = [1, 4, 9, 16]
>>> for i in s:
...     print(i)
...
1
4
9
16
>>>

À chaque itération de la boucle, vous obtenez un nouvel élément avec lequel travailler. Cette nouvelle valeur est placée dans la variable d'itération. Dans cet exemple, la variable d'itération est x :

for x in s:         ## `x` est une variable d'itération
  ...statements

À chaque itération, la valeur précédente de la variable d'itération est écrasée (le cas échéant). Après que la boucle ait fini, la variable conserve la dernière valeur.

Instruction break

Vous pouvez utiliser l'instruction break pour sortir d'une boucle prématurément.

for name in namelist:
    if name == 'Jake':
        break
  ...
  ...
statements

Lorsque l'instruction break est exécutée, elle sort de la boucle et passe aux statements suivants. L'instruction break ne s'applique qu'à la boucle la plus interne. Si cette boucle se trouve à l'intérieur d'une autre boucle, elle n'arrêtera pas la boucle externe.

Instruction continue

Pour sauter un élément et passer au suivant, utilisez l'instruction continue.

for line in lines:
    if line == '\n':    ## Sauter les lignes vides
        continue
    ## Plus d'instructions
 ...

Cela est utile lorsque l'élément actuel n'est pas d'intérêt ou doit être ignoré dans le traitement.

Boucler sur des entiers

Si vous avez besoin de compter, utilisez range().

for i in range(100):
    ## i = 0,1,...,99

La syntaxe est range([start,] end [,step])

for i in range(100):
    ## i = 0,1,...,99
for j in range(10,20):
    ## j = 10,11,..., 19
for k in range(10,50,2):
    ## k = 10,12,...,48
    ## Remarquez comment il compte par pas de 2, et non de 1.
  • La valeur de fin n'est jamais incluse. Elle reflète le comportement des tranches.
  • start est facultatif. Valeur par défaut : 0.
  • step est facultatif. Valeur par défaut : 1.
  • range() calcule les valeurs au fur et à mesure. Il ne stocke pas réellement une plage large de nombres.

Fonction enumerate()

La fonction enumerate ajoute une valeur de compteur supplémentaire à une itération.

names = ['Elwood', 'Jake', 'Curtis']
for i, name in enumerate(names):
    ## Boucle avec i = 0, name = 'Elwood'
    ## i = 1, name = 'Jake'
    ## i = 2, name = 'Curtis'

La forme générale est enumerate(sequence [, start = 0]). start est facultatif. Un bon exemple d'utilisation de enumerate() est le suivi des numéros de ligne lors de la lecture d'un fichier :

with open(filename) as f:
    for lineno, line in enumerate(f, start=1):
     ...

En fin de compte, enumerate n'est qu'un raccourci pratique pour :

i = 0
for x in s:
    statements
    i += 1

Utiliser enumerate nécessite moins de frappe et est légèrement plus rapide.

Boucles for et tuples

Vous pouvez itérer avec plusieurs variables d'itération.

points = [
  (1, 4),(10, 40),(23, 14),(5, 6),(7, 8)
]
for x, y in points:
    ## Boucle avec x = 1, y = 4
    ##            x = 10, y = 40
    ##            x = 23, y = 14
    ##           ...

Lorsque vous utilisez plusieurs variables, chaque tuple est déballé en un ensemble de variables d'itération. Le nombre de variables doit correspondre au nombre d'éléments de chaque tuple.

Fonction zip()

La fonction zip prend plusieurs séquences et crée un itérateur qui les combine.

columns = ['name','shares', 'price']
values = ['GOOG', 100, 490.1 ]
pairs = zip(columns, values)
## ('name','GOOG'), ('shares',100), ('price',490.1)

Pour obtenir le résultat, vous devez itérer. Vous pouvez utiliser plusieurs variables pour déballer les tuples comme montré précédemment.

for column, value in pairs:
  ...

Une utilisation courante de zip est de créer des paires clé/valeur pour construire des dictionnaires.

d = dict(zip(columns, values))

Exercice 2.13 : Compter

Essayez quelques exemples de comptage de base :

>>> for n in range(10):            ## Comptez de 0... 9
        print(n, end=' ')

0 1 2 3 4 5 6 7 8 9
>>> for n in range(10,0,-1):       ## Comptez de 10... 1
        print(n, end=' ')

10 9 8 7 6 5 4 3 2 1
>>> for n in range(0,10,2):        ## Comptez 0, 2,... 8
        print(n, end=' ')

0 2 4 6 8
>>>

Exercice 2.14 : Plus d'opérations sur les séquences

Expérimentez de manière interactive certaines des opérations de réduction de séquence.

>>> data = [4, 9, 1, 25, 16, 100, 49]
>>> min(data)
1
>>> max(data)
100
>>> sum(data)
204
>>>

Essayez de parcourir les données.

>>> for x in data:
        print(x)

4
9
...
>>> for n, x in enumerate(data):
        print(n, x)

0 4
1 9
2 1
...
>>>

Parfois, les débutants utilisent la structure for, la fonction len() et la fonction range() dans un fragment de code horrible qui semble sortir des profondeurs d'un programme C rouillé.

>>> for n in range(len(data)):
        print(data[n])

4
9
1
...
>>>

Ne faites pas ça! Non seulement ça fait mal aux yeux de tout le monde de le lire, mais c'est inefficace en termes de mémoire et ça exécute beaucoup plus lentement. Utilisez simplement une boucle for normale si vous voulez parcourir des données. Utilisez enumerate() si vous avez besoin de l'index pour une raison quelconque.

Exercice 2.15 : Un exemple pratique de enumerate()

Rappelez-vous que le fichier missing.csv contient des données pour un portefeuille d'actions, mais a quelques lignes avec des données manquantes. En utilisant enumerate(), modifiez votre programme pcost.py de sorte qu'il affiche un numéro de ligne avec le message d'avertissement lorsqu'il rencontre des données incorrectes.

>>> cost = portfolio_cost('/home/labex/project/missing.csv')
Ligne 4: Impossible de convertir : ['MSFT', '', '51.23']
Ligne 7: Impossible de convertir : ['IBM', '', '70.44']
>>>

Pour ce faire, vous devrez modifier quelques parties de votre code.

...
for rowno, row in enumerate(rows, start=1):
    try:
     ...
    except ValueError:
        print(f'Ligne {rowno} : Mauvaise ligne : {row}')
✨ Vérifier la solution et pratiquer

Exercice 2.16 : Utilisation de la fonction zip()

Dans le fichier portfolio.csv, la première ligne contient les en-têtes de colonne. Dans tout le code précédent, nous les avons ignorés.

>>> f = open('/home/labex/project/portfolio.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> headers
['name','shares', 'price']
>>>

Cependant, que se passe-t-il si vous pouvez utiliser les en-têtes pour quelque chose de pratique? C'est là que la fonction zip() entre en jeu. Essayez d'abord ceci pour associer les en-têtes de fichier à une ligne de données :

>>> row = next(rows)
>>> row
['AA', '100', '32.20']
>>> list(zip(headers, row))
[ ('name', 'AA'), ('shares', '100'), ('price', '32.20') ]
>>>

Remarquez comment zip() a associé les en-têtes de colonne aux valeurs de colonne. Nous avons utilisé list() ici pour convertir le résultat en une liste afin que vous puissiez le voir. Normalement, zip() crée un itérateur qui doit être consommé par une boucle for.

Cette association est une étape intermédiaire pour construire un dictionnaire. Maintenant, essayez ceci :

>>> record = dict(zip(headers, row))
>>> record
{'price': '32.20', 'name': 'AA','shares': '100'}
>>>

Cette transformation est l'un des trucs les plus utiles à connaître lorsqu'il s'agit de traiter de nombreux fichiers de données. Par exemple, supposons que vous vouliez faire en sorte que le programme pcost.py fonctionne avec différents fichiers d'entrée, mais sans vous soucier du numéro réel de colonne où apparaissent le nom, le nombre d'actions et le prix.

Modifiez la fonction portfolio_cost() dans pcost.py de sorte qu'elle ressemble à ceci :

## pcost.py

def portfolio_cost(filename):
 ...
        for rowno, row in enumerate(rows, start=1):
            record = dict(zip(headers, row))
            try:
                nshares = int(record['shares'])
                price = float(record['price'])
                total_cost += nshares * price
            ## Cela capture les erreurs dans les conversions de int() et float() ci-dessus
            except ValueError:
                print(f'Ligne {rowno} : Mauvaise ligne : {row}')
 ...

Maintenant, essayez votre fonction sur un fichier de données complètement différent portfoliodate.csv qui ressemble à ceci :

name,date,time,shares,price
"AA","6/11/2007","9:50am",100,32.20
"IBM","5/13/2007","4:20pm",50,91.10
"CAT","9/23/2006","1:30pm",150,83.44
"MSFT","5/17/2007","10:30am",200,51.23
"GE","2/1/2006","10:45am",95,40.37
"MSFT","10/31/2006","12:05pm",50,65.10
"IBM","7/9/2006","3:15pm",100,70.44
>>> portfolio_cost('/home/labex/project/portfoliodate.csv')
44671.15
>>>

Si vous avez fait cela correctement, vous constaterez que votre programme fonctionne toujours même si le fichier de données a un format de colonne complètement différent de celui d'avant. C'est génial!

Le changement apporté ici est subtil, mais important. Au lieu que portfolio_cost() soit codé en dur pour lire un seul format de fichier fixe, la nouvelle version lit n'importe quel fichier CSV et extrait les valeurs d'intérêt. Tant que le fichier a les colonnes requises, le code fonctionnera.

Modifiez le programme report.py que vous avez écrit dans la section 2.3 de sorte qu'il utilise la même technique pour extraire les en-têtes de colonne.

Essayez d'exécuter le programme report.py sur le fichier portfoliodate.csv et constatez qu'il produit la même réponse qu'auparavant.

✨ Vérifier la solution et pratiquer

Exercice 2.17 : Inversion d'un dictionnaire

Un dictionnaire associe des clés à des valeurs. Par exemple, un dictionnaire de prix d'actions.

>>> prices = {
        'GOOG' : 490.1,
        'AA' : 23.45,
        'IBM' : 91.1,
        'MSFT' : 34.23
    }
>>>

Si vous utilisez la méthode items(), vous pouvez obtenir des paires (clé,valeur) :

>>> prices.items()
dict_items([('GOOG', 490.1), ('AA', 23.45), ('IBM', 91.1), ('MSFT', 34.23)])
>>>

Cependant, que se passe-t-il si vous voulez obtenir une liste de paires (valeur, clé) à la place? Indice : utilisez zip().

>>> pricelist = list(zip(prices.values(),prices.keys()))
>>> pricelist
[(490.1, 'GOOG'), (23.45, 'AA'), (91.1, 'IBM'), (34.23, 'MSFT')]
>>>

Pourquoi feriez-vous cela? Pour commencer, cela vous permet de réaliser certains types de traitement de données sur les données du dictionnaire.

>>> min(pricelist)
(23.45, 'AA')
>>> max(pricelist)
(490.1, 'GOOG')
>>> sorted(pricelist)
[(23.45, 'AA'), (34.23, 'MSFT'), (91.1, 'IBM'), (490.1, 'GOOG')]
>>>

Cela illustre également une caractéristique importante des tuples. Lorsqu'ils sont utilisés dans des comparaisons, les tuples sont comparés élément par élément, en commençant par le premier élément. De la même manière que les chaînes de caractères sont comparées caractère par caractère.

zip() est souvent utilisé dans des situations comme celle-ci où vous devez associer des données provenant de différents emplacements. Par exemple, en associant les noms de colonnes aux valeurs de colonne afin de créer un dictionnaire de valeurs nommées.

Notez que zip() n'est pas limité à des paires. Par exemple, vous pouvez l'utiliser avec n'importe quel nombre de listes d'entrée :

>>> a = [1, 2, 3, 4]
>>> b = ['w', 'x', 'y', 'z']
>>> c = [0.2, 0.4, 0.6, 0.8]
>>> list(zip(a, b, c))
[(1, 'w', 0.2), (2, 'x', 0.4), (3, 'y', 0.6), (4, 'z', 0.8))]
>>>

De plus, sachez que zip() s'arrête une fois que la plus courte séquence d'entrée est épuisée.

>>> a = [1, 2, 3, 4, 5, 6]
>>> b = ['x', 'y', 'z']
>>> list(zip(a,b))
[(1, 'x'), (2, 'y'), (3, 'z')]
>>>

Sommaire

Félicitations! Vous avez terminé le laboratoire sur les séquences. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.