106 votes

Comment puis-je effectuer des travaux dans une liste de compréhension ?

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

Le code suivant est une syntaxe invalide. Je veux mettre lst[0] à une chaîne vide '' s'il correspond à pattern :

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

Merci de votre attention !

100voto

n1k31t4 Points 755

Python 3.8 introduira Expressions d'affectation .

Il s'agit d'un nouveau symbole : := qui permet l'affectation dans (entre autres) les compréhensions. Ce nouvel opérateur est également connu sous le nom de l'opérateur morse .

Elle permettra de réaliser de nombreuses économies potentielles en matière de calcul et de mémoire, comme le montre l'extrait suivant de la PEP mentionnée ci-dessus (formatage adapté pour la SO) :

Syntaxe et sémantique

Dans la plupart des contextes où l'arbitrage peut apparaître. Elle est de la forme NAME := expr w expr est toute expression Python valide autre qu'une expression non parenthésée et NAME est un identifiant.

La valeur d'un tel nom expressi avec l'effet secondaire supplémentaire que cette valeur est attribuée à la cible. cette valeur :

  1. Traiter une expression rationnelle correspondante

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

    while chunk := file.read(8192):
        process(chunk)
  3. Réutiliser 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 récemment publiée (non recommandée pour les systèmes de production !). Vous pouvez trouver le calendrier de publication de Python 3.8 ici .

37voto

dawg Points 26051

Il semble que vous confondiez compréhension de la liste con Constructions en boucle en Python.

La compréhension d'une liste produit -- une liste ! Elle ne se prête pas à une affectation unique dans une liste existante. (Bien qu'il soit possible de torturer la syntaxe pour le faire...)

Bien que ce que vous essayez de faire à partir de votre code ne soit pas exactement clair, je pense que cela ressemble plus à une boucle sur la liste (contrôle de flux) qu'à la production d'une liste (compréhension de liste).

Passez en boucle sur la liste comme suit :

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

C'est une façon raisonnable de procéder, et c'est ce que vous feriez en C, en Pascal, etc. Mais vous pouvez également tester la liste pour une seule valeur et la modifier :

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 que vous 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 liste, ou une carte, ou l'un des nombreux autres outils du kit Python.

Personnellement, j'ai tendance à utiliser les compréhensions de listes plutôt 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, qu'est-ce qui est le plus compréhensible ?

Ceci :

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

ou ceci :

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

YMMV

Ici est un excellent tutoriel à ce sujet.

17voto

6502 Points 42700

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

L'affectation est une déclaration, même si la syntaxe fait parfois croire qu'il s'agit d'une expression (par ex. a=b=99 fonctionne, mais il s'agit d'un cas de syntaxe particulier et cela ne signifie pas que l'option b=99 est une expression comme c'est le cas par exemple en C).

Les compréhensions de listes sont plutôt des expressions parce qu'elles renvoient une valeur ; dans un sens, la boucle qu'elles exécutent est un incident et le point principal est la liste renvoyée.

Une déclaration peut contenir des expressions, mais une expression ne peut pas contenir de déclarations.

Cela dit, l'affectation d'éléments de liste est convertie en interne en appel de méthode (pour permettre la création d'objets de type liste) et les appels de méthode 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 une mauvaise chose car cela nuit à la lisibilité et la facilité de lecture du code source est l'élément le plus important. axe principal en langage Python. Vous devriez plutôt écrire par exemple...

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

que, soit dit en passant, grâce à la in est équivalent à l'opérateur encore plus lisible

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

Les compréhensions de listes sont utilisées pour leur valeur de retour et elles forment une boucle en interne... Si ce que vous voulez, c'est la boucle, alors écrivez simplement une boucle... ceux qui liront le code en essayant de comprendre ce qu'il fait apprécieront beaucoup cela (et ceux qui incluent vous-même dans quelques semaines).

9voto

Colin Valliant Points 1310

En bref : vous n'en avez pas. Les compréhensions de listes servent à générer des listes, pas à modifier des listes existantes. Si vous souhaitez modifier une liste, utilisez une boucle for, car c'est à cela qu'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 faire de l'affectation à l'intérieur d'un code, et que vous ne voulez pas que tous les programmeurs Python qui ont affaire à votre code le détestent pour l'éternité, il y a quelques fonctions que vous pouvez utiliser :

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

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

        list.__setitem__(index, value)

2voto

Zubair Hassan Points 65

Comme indiqué dans les réponses ci-dessus, il n'y a pas d'affectation directe possible dans la fonction de compréhension de liste, mais il y a un moyen détournable de le faire en utilisant la fonction exec pour réaliser la mission.

Pas seulement assignments nous pouvons passer n'importe quelle expression python dans exec pour l'évaluer.

Dans votre cas, cela pourrait se faire de la manière suivante

  [ exec(f"lst[0] = ''") for pattern in start_pattern if lst[0] == pattern ]

Si nous disposons d'une liste d'objets et que nous voulons attribuer une valeur à un attribut spécifique de l'objet à une condition spécifique, cela pourrait se faire comme suit :

[ exec("p.age_status=child") for p in persons_obj_list if p.age <= 18 ]

Remarque : cette opération modifie l'état des objets existants d'une liste et ne renvoie pas la liste d'objets telle qu'elle est renvoyée dans le cadre d'une utilisation normale de l'interprétation des listes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X