Introduction
Une tâche courante consiste à traiter les éléments d'une liste. Cette section présente les compréhensions de liste, un outil puissant pour faire exactement cela.
Création de nouvelles listes
Une compréhension de liste crée une nouvelle liste en appliquant une opération à chaque élément d'une séquence.
>>> a = [1, 2, 3, 4, 5]
>>> b = [2*x for x in a ]
>>> b
[2, 4, 6, 8, 10]
>>>
Un autre exemple :
>>> names = ['Elwood', 'Jake']
>>> a = [name.lower() for name in names]
>>> a
['elwood', 'jake']
>>>
La syntaxe générale est : [ <expression> for <variable_name> in <sequence> ].
Filtrer
Vous pouvez également filtrer lors de la compréhension de liste.
>>> a = [1, -5, 4, 2, -2, 10]
>>> b = [2*x for x in a if x > 0 ]
>>> b
[2, 8, 4, 20]
>>>
Cas d'utilisation
Les compréhensions de liste sont d'une utilité immense. Par exemple, vous pouvez collecter les valeurs d'un champ spécifique d'un dictionnaire :
stocknames = [s['name'] for s in stocks]
Vous pouvez effectuer des requêtes similaires à celles d'une base de données sur des séquences.
a = [s for s in stocks if s['price'] > 100 and s['shares'] > 50 ]
Vous pouvez également combiner une compréhension de liste avec une réduction de séquence :
cost = sum([s['shares']*s['price'] for s in stocks])
Syntaxe générale
[ <expression> for <variable_name> in <sequence> if <condition>]
Ce que cela signifie :
result = []
for variable_name in sequence:
if condition:
result.append(expression)
Détour historique
Les compréhensions de liste viennent des mathématiques (notation de construction d'ensemble).
a = [ x * x for x in s if x > 0 ] ## Python
a = { x^2 | x ∈ s, x > 0 } ## Math
Elle est également implémentée dans plusieurs autres langages. La plupart des programmeurs ne pensent probablement pas à leur cours de mathématiques cependant. Il est donc acceptable de la considérer comme un raccourci pratique pour les listes.
Exercice 2.19 : Compréhensions de liste
Essayez quelques compréhensions de liste simples pour vous familiariser avec la syntaxe.
>>> nums = [1,2,3,4]
>>> squares = [ x * x for x in nums ]
>>> squares
[1, 4, 9, 16]
>>> twice = [ 2 * x for x in nums if x > 2 ]
>>> twice
[6, 8]
>>>
Remarquez comment les compréhensions de liste créent une nouvelle liste avec les données convenablement transformées ou filtrées.
Exercice 2.20 : Réductions de séquence
Calculez le coût total du portefeuille en utilisant une seule instruction Python.
>>> portfolio = read_portfolio('portfolio.csv')
>>> cost = sum([ s['shares'] * s['price'] for s in portfolio ])
>>> cost
44671.15
>>>
Une fois que vous avez fait cela, montrez comment vous pouvez calculer la valeur actuelle du portefeuille en utilisant une seule instruction.
>>> value = sum([ s['shares'] * prices[s['name']] for s in portfolio ])
>>> value
28686.1
>>>
Les deux opérations ci-dessus sont des exemples de map-réduction. La compréhension de liste effectue une opération sur chaque élément de la liste.
>>> [ s['shares'] * s['price'] for s in portfolio ]
[3220.0000000000005, 4555.0, 12516.0, 10246.0, 3835.1499999999996, 3254.9999999999995, 7044.0]
>>>
La fonction sum() effectue ensuite une réduction sur le résultat :
>>> sum(_)
44671.15
>>>
Avec ces connaissances, vous êtes maintenant prêt à lancer une startup de big data.
Exercice 2.21 : Requêtes sur des données
Essayez les exemples suivants de diverses requêtes sur des données.
Tout d'abord, une liste de toutes les positions du portefeuille avec plus de 100 actions.
>>> more100 = [ s for s in portfolio if s['shares'] > 100 ]
>>> more100
[{'price': 83.44, 'name': 'CAT','shares': 150}, {'price': 51.23, 'name': 'MSFT','shares': 200}]
>>>
Toutes les positions du portefeuille pour les actions MSFT et IBM.
>>> msftibm = [ s for s in portfolio if s['name'] in {'MSFT','IBM'} ]
>>> msftibm
[{'price': 91.1, 'name': 'IBM','shares': 50}, {'price': 51.23, 'name': 'MSFT','shares': 200},
{'price': 65.1, 'name': 'MSFT','shares': 50}, {'price': 70.44, 'name': 'IBM','shares': 100}]
>>>
Une liste de toutes les positions du portefeuille qui coûtent plus de 10 000 $.
>>> cost10k = [ s for s in portfolio if s['shares'] * s['price'] > 10000 ]
>>> cost10k
[{'price': 83.44, 'name': 'CAT','shares': 150}, {'price': 51.23, 'name': 'MSFT','shares': 200}]
>>>
Exercice 2.22 : Extraction de données
Montrez comment vous pourriez construire une liste de tuples (nom, nombre d'actions) où nom et nombre d'actions sont extraits de portfolio.
>>> name_shares =[ (s['name'], s['shares']) for s in portfolio ]
>>> name_shares
[('AA', 100), ('IBM', 50), ('CAT', 150), ('MSFT', 200), ('GE', 95), ('MSFT', 50), ('IBM', 100)]
>>>
Si vous changez les crochets ([, ]) en accolades ({, }), vous obtenez ce qu'on appelle une compréhension de ensemble. Cela vous donne des valeurs uniques ou distinctes.
Par exemple, cela détermine l'ensemble des noms d'actions uniques qui apparaissent dans portfolio :
>>> names = { s['name'] for s in portfolio }
>>> names
{ 'AA', 'GE', 'IBM', 'MSFT', 'CAT' }
>>>
Si vous spécifiez des paires clé:valeur, vous pouvez construire un dictionnaire. Par exemple, créez un dictionnaire qui associe le nom d'une action au nombre total d'actions détenues.
>>> holdings = { name: 0 for name in names }
>>> holdings
{'AA': 0, 'GE': 0, 'IBM': 0, 'MSFT': 0, 'CAT': 0}
>>>
Cette dernière fonction est connue sous le nom de compréhension de dictionnaire. Tabulons :
>>> for s in portfolio:
holdings[s['name']] += s['shares']
>>> holdings
{ 'AA': 100, 'GE': 95, 'IBM': 150, 'MSFT':250, 'CAT': 150 }
>>>
Essayez cet exemple qui filtre le dictionnaire prices pour ne conserver que les noms qui apparaissent dans le portefeuille :
>>> portfolio_prices = { name: prices[name] for name in names }
>>> portfolio_prices
{'AA': 9.22, 'GE': 13.48, 'IBM': 106.28, 'MSFT': 20.89, 'CAT': 35.46}
>>>
Exercice 2.23 : Extraction de données à partir de fichiers CSV
Savoir utiliser diverses combinaisons de compréhensions de listes, d'ensembles et de dictionnaires peut être utile dans diverses formes de traitement de données. Voici un exemple qui montre comment extraire des colonnes sélectionnées à partir d'un fichier CSV.
Tout d'abord, lisez une ligne d'informations d'en-tête à partir d'un fichier CSV :
>>> import csv
>>> f = open('portfoliodate.csv')
>>> rows = csv.reader(f)
>>> headers = next(rows)
>>> headers
['name', 'date', 'time','shares', 'price']
>>>
Ensuite, définissez une variable qui liste les colonnes qui vous intéressent réellement :
>>> select = ['name','shares', 'price']
>>>
Maintenant, localisez les indices des colonnes ci-dessus dans le fichier CSV source :
>>> indices = [ headers.index(colname) for colname in select ]
>>> indices
[0, 3, 4]
>>>
Enfin, lisez une ligne de données et convertissez-la en un dictionnaire en utilisant une compréhension de dictionnaire :
>>> row = next(rows)
>>> record = { colname: row[index] for colname, index in zip(select, indices) } ## dict-comprehension
>>> record
{'price': '32.20', 'name': 'AA','shares': '100'}
>>>
Si vous vous sentez à l'aise avec ce qui vient de se passer, lisez le reste du fichier :
>>> portfolio = [ { colname: row[index] for colname, index in zip(select, indices) } for row in rows ]
>>> portfolio
[{'price': '91.10', 'name': 'IBM','shares': '50'}, {'price': '83.44', 'name': 'CAT','shares': '150'},
{'price': '51.23', 'name': 'MSFT','shares': '200'}, {'price': '40.37', 'name': 'GE','shares': '95'},
{'price': '65.10', 'name': 'MSFT','shares': '50'}, {'price': '70.44', 'name': 'IBM','shares': '100'}]
>>>
Oh mon Dieu, vous venez de réduire une grande partie de la fonction read_portfolio() à une seule instruction.
Commentaire
Les compréhensions de listes sont couramment utilisées en Python comme moyen efficace de transformer, de filtrer ou de collecter des données. En raison de la syntaxe, il ne faut pas abuser - essayez de garder chaque compréhension de liste aussi simple que possible. Il est acceptable de diviser les choses en plusieurs étapes. Par exemple, il n'est pas évident que vous voudriez surprendre vos collègues inattendus avec le dernier exemple.
Cela étant dit, savoir manipuler rapidement les données est une compétence incroyablement utile. Il existe de nombreuses situations où vous devriez peut-être résoudre un problème unique de type import, export, extraction de données, etc. Devenir un maître des compréhensions de listes peut considérablement réduire le temps passé à concevoir une solution. N'oubliez pas également le module collections.
Sommaire
Félicitations ! Vous avez terminé le laboratoire sur les compréhensions de listes. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.