web-dev-qa-db-fra.com

python compréhension de liste avec plusieurs if

Nous connaissons tous les pythons

[f(x) for x in y if g(x)]

syntaxe.

Cependant, la représentation AST de la compréhension de la liste peut contenir plus d'une expression "si":

comprehension = (expr target, expr iter, expr* ifs)

Quelqu'un peut-il me donner un exemple de code python qui produirait un AST avec plus d'une expression 'if'?)

34
Stefan

Il suffit de les empiler les uns après les autres:

[i for i in range(100) if i > 10 if i < 50]

Produit les entiers entre 11 et 49 inclus.

47
Emil Vikström

La grammaire permet plusieurs instructions if car vous pouvez les mélanger entre les boucles for:

[j for i in range(100) if i > 10 for j in range(i) if j < 20]

Les composants de compréhension doivent être considérés comme des instructions imbriquées, ce qui se traduit par:

lst = []
for i in range(100):
    if i > 10:
        for j in range(i):
            if j < 20:
                lst.append(j)

Cela signifie également que vous pouvez utiliser plusieurs instructions if sans boucles for entre les deux:

[i for i in range(100) if i > 10 if i < 20]

Bien que non sensible (combinez simplement ceux utilisant and ou avec des opérateurs chaînés), cela se traduit toujours par un ensemble d'instructions imbriquées légales:

lst = []
for i in range(100):
    if i > 10:
        if i < 20:
            lst.append(i)

La grammaire et l'analyseur ne refusent pas spécifiquement cette utilisation , de la même manière que Python ne vous interdit pas de instructions nest if.

Notez que PEP 202 - Liste des compréhensions (le document de proposition original qui a ajouté cette fonctionnalité à la langue) comprend en fait un double- si compréhension dans la section des exemples:

>>> print [(i, f) for i in nums for f in fruit if f[0] == "P" if i%2 == 1]
[(1, 'Peaches'), (1, 'Pears'), (3, 'Peaches'), (3, 'Pears')]
49
Martijn Pieters

L'utilisation de la fonction all() intégrée vous permet de placer plusieurs expressions ou fonctions booléennes dans un itérable et de rester fidèle à votre compréhension. Je pense que c'est un joli sous-utilisé intégré et il maintient la lisibilité élevée.

>>> [x for x in range(20) if all([1 < x < 10, not x & 1])]
[2, 4, 6, 8]

Ou

>>> [x for x in range(20) if all([foo(x), bar(x)])]

la any() intégrée fonctionnerait également bien ici si une seule condition devait être remplie:

>>> [x for x in range(20) if any([1 < x < 10, not x & 1])]
[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18]
12
kylie.a

Le référence du langage donne une meilleure idée à ce sujet:

list_comprehension  ::=  expression list_for
list_for            ::=  "for" target_list "in" old_expression_list [list_iter]
list_iter           ::=  list_for | list_if
list_if             ::=  "if" old_expression [list_iter]

Comme vous pouvez le voir, la compréhension de la liste est définie avec un list_iter Facultatif à la fin - un seul list_iter. Maintenant, ce list_iter Peut être une autre partie de la compréhension de la liste ou une condition if. La condition if elle-même se termine à nouveau avec un autre list_iter Facultatif. Ceci est essentiel pour permettre de chaîner plusieurs pièces détachées avec des conditions if facultatives dans la même compréhension de liste. Le fait que vous puissiez également construire une pièce .. if X if Y if Z Pour le list_iter N'est qu'un effet secondaire.

Ainsi, bien que la possibilité de chaîner plusieurs conditions if seules ne soit pas nécessaire, elle permet à toute la grammaire d'être définie de cette façon.

5
poke