web-dev-qa-db-fra.com

Comment puis-je faire des devoirs dans une compréhension de liste?

Je veux utiliser l'opérateur d'affectation dans une compréhension de liste. Comment puis je faire ça?

Le code suivant est une syntaxe non valide. Je veux définir lst[0] avec une chaîne vide '' si elle correspond à pattern:

[ lst[0] = '' for pattern in start_pattern if lst[0] == pattern ]

Merci!

32
xunzhang

Il semble que vous confondiez la compréhension de la liste avec les constructions en boucle en Python. 

Une liste de compréhension produit - une liste! Il ne se prête pas à une seule tâche dans une liste existante. (Bien que vous puissiez torturer la syntaxe pour le faire ...)

Bien que ce que vous essayez de faire avec votre code ne soit pas tout à fait clair, je pense que cela ressemble plus à faire une boucle sur la liste (contrôle de flux) ou produire une liste (compréhension de liste) 

Boucle sur la liste comme ceci:

for pattern in patterns:
   if lst[0] == pattern: lst[0]=''

C’est une façon raisonnable de le faire. C’est ce que vous feriez en C, Pascal, etc. Mais vous pouvez aussi simplement tester la liste pour une valeur et la changer: 

if lst[0] in patterns: lst[0] = ''

Ou, si vous ne connaissez pas l'index:

i=lst.index[pattern]
lst[i]=''

ou, si vous avez une liste de listes et souhaitez modifier chaque premier élément de chaque sous-liste:

for i, sublst in enumerate(lst):
    if sublst[i][0] in patterns: sublist[i][0]=''

etc, etc, etc. 

Si vous souhaitez appliquer quelque chose à chaque élément d'une liste, vous pouvez utiliser une compréhension de la liste, une carte ou l'un des nombreux autres outils du kit Python. 

Personnellement, j’ai tendance à utiliser davantage les compréhensions de liste pour la création de listes:

 l=[[ x for x in range(5) ] for y in range(4)]  #init a list of lists...

Ce qui est plus naturel que:

l=[]
for i in range(4):
   l.append([])
   for j in range(5):
      l[i].append(j)      

Mais pour modifier cette même liste de listes, qui est plus compréhensible?

Ce:

l=[['new value' if j==0 else l[i][j] for j in range(len(l[i]))] for i in range(len(l))]

ou ca:

for i,outter in enumerate(l):
    l[i][0]='new value'               

YMMV

Ici est un excellent tutoriel à ce sujet.

21
dawg

Le langage Python a des concepts distincts pour les expressions et les déclarations.

L'affectation est une instruction même si la syntaxe vous amène parfois à croire qu'il s'agit d'une expression (par exemple, a=b=99 fonctionne mais est un cas de syntaxe spécial et ne signifie pas que b=99 est une expression telle qu'elle est par exemple en C).

Les interprétations de liste sont plutôt des expressions car elles renvoient une valeur. En un sens, la boucle qu'elles exécutent est un incident et le point principal est la liste renvoyée.

Une instruction peut contenir des expressions mais une expression ne peut pas contenir d'instructions.

Cela dit, l'assigment d'élément de liste est converti en interne en un appel de méthode (pour permettre la création d'objets de type liste) et les appels de méthodes sont des expressions. Par conséquent, vous pouvez techniquement utiliser l'affectation d'éléments de liste dans une expression:

[ lst.__setitem__(0, '') for pattern in start_pattern if lst[0] == pattern ]

Ceci est cependant considéré comme mauvais car cela nuit à la lisibilité et la facilité de lecture du code source est l’intérêt principal dans le langage Python. Vous devriez écrire à la place par exemple ...

for pattern in start_pattern:
    if lst[0] == pattern:
        lst[0] = ''

qu’au fait, grâce à l’opérateur in est équivalent à l’opérateur encore plus lisible

if lst[0] in start_pattern:
    lst[0] = ''

Les interprétations de liste sont utilisées pour leur valeur de retour et font une boucle en interne ... Si ce que vous voulez est la boucle, écrivez simplement une boucle ... Celui qui lira le code en essayant de comprendre ce qu’il fait apprécierait beaucoup (et quiconque vous comprend dans quelques semaines).

9
6502

En bref: vous ne le faites pas. Les compréhensions de liste servent à générer des listes, pas à modifier des listes existantes. Si vous souhaitez modifier une liste, utilisez une boucle for, car c'est à quoi elles servent.

La façon pythonique d’écrire ce code serait quelque chose comme:

for pattern in start_pattern:
    if lst[0] == pattern:
        lst[0] = ''
        #the following assumes that pattern will never be ''
        #if that's possible, you can ignore this bit
        break

Cependant, si vous voulez vraiment, vraiment, assigner une tâche à l'intérieur de celle-ci, et ne dérange pas tous les programmeurs Python qui traitent votre code le haïssant pour l'éternité, vous pouvez utiliser quelques fonctions:

  • Si la variable que vous voulez assigner est une variable globale, alors vous pouvez faire

        globals().update(var=value)
    
  • Si la variable que vous souhaitez affecter est une séquence mutable ou une carte (telle qu'une liste ou un dict)

        list.__setitem__(index, value)
    
5
Colin Valliant

Si ce que vous dites dans la question est:

[ lst[0] = '' for lst in listOfLists if lst[0] == pattern ]

ou pour une liste de motifs

[ lst[0] = '' for lst in listOfLists if lst[0] in patterns ]

Cela peut être fait facilement

[ [''] + lst[1:] for lst in listOfLists if lst[0] == pattern ]

ou pour une liste de modèles à nouveau

[[''] + lst[1:] for lst in listOfLists if lst[0] in patterns ]
0
Jamie Marshall

Python 3.8 introduira les expressions Assignment Expressions .

C'est un nouveau symbole: := qui permet une affectation dans les compréhensions, entre autres.

Cela introduira beaucoup d'économies potentielles avec w.r.t. calcul/mémoire, comme le montre l'extrait suivant du PEP lié ci-dessus (mise en forme adaptée à SO):

Syntaxe et sémantique

Dans la plupart des contextes où des expressions Python arbitraires peuvent être utilisées, un expression nommée peut apparaître. C'est de la forme NAME := exprexpr est une expression Python valide autre qu'un.. Tuple, et NAME est un identifiant.

La valeur d'une telle expression nommée est la même que celle incorporée expression, avec l’effet secondaire supplémentaire que la cible est assigné cette valeur:

  1. Gérer une regex correspondante

    if (match := pattern.search(data)) is not None:
        # Do something with match
    
  2. Une boucle qui ne peut pas être réécrite trivialement avec 2-arg iter ()

    while chunk := file.read(8192):
        process(chunk)
    
  3. Réutilise une valeur coûteuse à calculer

    [y := f(x), y**2, y**3]
    
  4. Partager une sous-expression entre une clause de filtre de compréhension et sa sortie

    filtered_data = [y for x in data if (y := f(x)) is not None]
    

Ceci est déjà disponible dans la version alpha des dernières versions (non recommandé pour les systèmes de production!). Vous pouvez trouver le calendrier de publication de Python 3.8 ici .

0
n1k31t4