Posté par al al le 7 juin 2011

collections python

Astuces sur les collections en Python

Après une journée difficile j'ai envie de me détendre en vous proposant une petite série d'astuces sur les collections en Python. Rien de bien sorcier ici mais des petits trucs que tout le monde ne connaît pas forcément, comme j'ai pu m'en apercevoir en lisant le code des autres. C'est aussi un prétexte pour un test <cite>real-world</cite> du blog de MySmeuh.

Tester si une liste est vide

Nul besoin d'avoir recours à len() pour savoir si une liste est vide puisque une liste vide est considérée comme fausse. Donc pas besoin de dire:

if len(maliste):
    # Faire quelque chose de ma liste
else:
    # La liste est vide

On peut simplement dire:

if maliste:
    # Faire quelque chose de ma liste
else:
    # La liste est vide

Obtenir l'index des éléments d'une liste qu'on parcourt

Parfois on a besoin de parcourir une liste et de connaître l'index de chaque élément.

Par pitié ne faites pas:

i = 0
for elem in maliste:
    # Faire quelque chose avec i et elem
    i += 1

Mais faites simplement:

for i, elem in enumerate(maliste):
    # Faire quelque chose avec i et elem

Trier une liste

Il arrive souvent qu'on ait besoin de trier une liste en fonction d'une caractéristique des éléments qui la composent. Ici par exemple, on veut trier des éléments en fonction de leur attribut plop.

class Toto(object):
    def __init__(self, plop):
        self.plop = plop

maliste = [Toto(4), Toto(8), Toto(2)]

def trieur(elem):
    return elem.plop

for elem in sorted(maliste, key=trieur):
    print elem.plop

On a défini une fonction trieur qui nous sert à extraire la valeur sur laquelle sera fait le tri. En fait ce genre de tri est tellement courant que le bibliothèque standard inclut des fonctions déjà toute faites pour ça dans le module operator:

from operator import attrgetter

for elem in sorted(maliste, key=attrgetter('plop')):
    print elem.plop

Voilà c'est quelque caractères de gagnés (une lambda aurait été pas mal non plus) mais surtout c'est légèrement plus lisible. À vous de voir si ça vous convient. Il y aussi itemgetter et methodcaller dont vous devinez sûrement l'usage.

Regrouper des éléments

La dernière astuce concerne les dictionnaires. Une tache courante avec les listes consiste à regrouper ses éléments en fonction d'un critère. On construit alors un dictionnaire indexé par ce critère. La méthode classique ressemble à ceci:

class Toto(object):
    def __init__(self, plop):
        self.plop = plop

maliste = [Toto(4), Toto(3), Toto(4), Toto(2), Toto(3)]

mondict = {}

for elem in maliste:
    if elem.plop in mondict:
        mondict[elem.plop].append(elem)
    else:
        mondict[elem.plop] = [elem]

À chaque tour de boucle on teste si la clé est présente à l'aide de in. Si elle ne l'est pas il faut initialiser la liste pour cette clé.

Le module collection propose le type defaultdict qui simplifie légèrement la procédure.

from collections import defaultdict

mondict = defaultdict(list)

for elem in maliste:
    mondict[elem.plop].append(elem)

Quand on crée le defaultdict, on lui passe un callable qui sera appelé pour créer la valeur d'une clé manquante. Ici on lui passe list, donc pour toute nouvelle clé c'est une liste qui sera créée.

Merci

Voilà c'est tout les amis. Si vous connaissez des astuces encore plus extraordinaires ou si vous trouvez que les miennes sont toutes pourries, lâchez vous dans les comz !-)

À l'année prochaine !

Commentaires sur ce billet

Merci de vous authentifier (ou vous inscrire) pour laisser un commentaire

Voir le code source en reStructuredText