Yield From: Comment aplatir une séquence imbriquée en Python

Vous avez une séquence imbriquée que vous voulez aplatir en une seule liste de valeurs. Ceci est facilement résolu en écrivant une fonction de générateur récursif impliquant l’instruction yield from. Par exemple:

from collections import Iterable

def aplatir(elements, ignore_types=(str, bytes)):
    for x in elements:
        if isinstance(x, Iterable) and not isinstance(x, ignore_types):
            yield from aplatir(x, ignore_types)
        else:
            yield x

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

# Produit 1 2 3 4 5 6 7 8
for x in aplatir(elements):
    print(x)

Dans le code, isinstance(x, Iterable) vérifie tout simplement si un élément est itérable.

Si c’est le cas, l’instrcution yield from est utilisée pour délivrer toutes ses valeurs sous la forme d’une sorte de sous-routine. Le résultat final est une seule séquence de sortie sans imbrication.

L’argument supplémentaire ignore_types et la vérification de not isinstance(x, ignore_types) sont là pour empêcher que les chaînes de caractères et les octets soient interprétés comme itérables et élargis en caractères individuels.

Cela permet à des listes imbriquées de chaînes de caractères de fonctionner comme la plupart des gens s’y attendent. Par exemple:

>>> elements= ['Appale', 'MS', ['IBM', 'HP']]
>>> for x in aplatir(elements):
...     print(x)
...
Apple
MS
IBM
HP
>>>

L’instruction yield from est un joli raccourci à utiliser si vous voulez écrire des générateurs qui appellent d’autres générateurs comme sous-routines. Si vous ne l’utilisez pas, vous devez écrire un code qui utilise une extra boucle for. Par exemple:

def aplatir(elements, ignore_types=(str, bytes)):
    for x in elements:
        if isinstance(x, Iterable) and not isinstance(x, ignore_types):
            for i in aplatir(x):
                yield i
        else:
            yield x

Bien qu’il ne s’agisse que d’un changement mineur, l’instruction yield from est tout simplement plus agréable et conduit à un code plus propre.

Comme indiqué, le contrôle supplémentaire pour les chaînes de caractères et les octets est là pour empêcher l’expansion de ces types en caractères individuels.

S’il y a d’autres types que vous ne voulez pas développer, vous pouvez fournir une valeur différente pour l’argument ignore_types.

Enfin, il convient de noter que yield from a un rôle plus important dans les programmes avancés impliquant des coroutines et la concurrence par générateur.

LAISSER UN COMMENTAIRE

Please enter your comment!
Please enter your name here