web-dev-qa-db-fra.com

Est-ce Pythonic d'utiliser des compréhensions de liste pour juste des effets secondaires?

Pensez à une fonction que j'appelle pour ses effets secondaires, pas pour renvoyer des valeurs (comme l'impression à l'écran, la mise à jour de l'interface graphique, l'impression dans un fichier, etc.).

def fun_with_side_effects(x):
    ...side effects...
    return y

Maintenant, est-ce Pythonic d'utiliser des compréhensions de liste pour appeler cette fonction:

[fun_with_side_effects(x) for x in y if (...conditions...)]

Notez que je n'enregistre la liste nulle part

Ou devrais-je appeler cette fonction comme ceci:

for x in y:
    if (...conditions...):
        fun_with_side_effects(x)

Quel est le meilleur et pourquoi?

101
sinan

C'est très anti-Pythonique de le faire, et n'importe quel Pythonista chevronné vous en donnera plein la vue. La liste intermédiaire est jetée après sa création, et elle peut potentiellement être très, très grande et donc coûteuse à créer.

76

Vous ne devriez pas utiliser une compréhension list, car comme les gens l'ont dit, cela créera une grande liste temporaire dont vous n'avez pas besoin. Les deux méthodes suivantes sont équivalentes:

consume(side_effects(x) for x in xs)

for x in xs:
    side_effects(x)

avec la définition de consume dans la page de manuel itertools:

def consume(iterator, n=None):
    "Advance the iterator n-steps ahead. If n is none, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

Bien sûr, ce dernier est plus clair et plus facile à comprendre.

31
Katriel

La compréhension des listes sert à créer des listes. Et à moins que vous ne créiez réellement une liste, vous devez pas utiliser des compréhensions de liste.

Donc, j'obtiendrais pour la deuxième option, itérant simplement sur la liste, puis appelais la fonction lorsque les conditions s'appliquaient.

20
Ikke

C'est mieux.

Pensez à la personne qui aurait besoin de comprendre votre code. Vous pouvez facilement obtenir un mauvais karma avec le premier :)

Vous pouvez aller au milieu entre les deux en utilisant filter (). Prenons l'exemple:

y=[1,2,3,4,5,6]
def func(x):
    print "call with %r"%x

for x in filter(lambda x: x>3, y):
    func(x)
11
user237419

Cela dépend de votre objectif.

Si vous essayez d'effectuer une opération sur chaque objet d'une liste, la deuxième approche doit être adoptée.

Si vous essayez de générer une liste à partir d'une autre liste, vous pouvez utiliser la compréhension de liste.

Explicite vaut mieux qu'implicite. Simple, c'est mieux que complexe. (Python Zen)

3
rubayeet

Tu peux faire

for z in (fun_with_side_effects(x) for x in y if (...conditions...)): pass

mais ce n'est pas très joli.

0
sigs