web-dev-qa-db-fra.com

Ajout d'un élément aux listes dans une compréhension de liste

J'ai une liste, disons, a = [[1,2],[3,4],[5,6]]

Je veux ajouter la chaîne 'a' à chaque élément de la liste a.

Quand j'utilise:

a = [x.append('a') for x in a] 

il renvoie [None,None,None].

Mais si j'utilise:

a1 = [x.append('a') for x in a]

alors il fait quelque chose d'étrange.

a, mais pas a1 est [[1,2,'a'],[3,4,'a'],[5,6,'a']].

Je ne comprends pas pourquoi le premier appel renvoie [None, None, None] ni pourquoi le second change sur a au lieu de a1.

25
ariel

list.append mute la liste elle-même et renvoie None. Les compréhensions de liste servent à stocker le résultat, ce qui n'est pas ce que vous voulez dans ce cas si vous souhaitez simplement modifier les listes d'origine.

>>> x = [[1, 2], [3, 4], [5, 6]]
>>> for sublist in x:
...     sublist.append('a')
...
>>> x
[[1, 2, 'a'], [3, 4, 'a'], [5, 6, 'a']]
35
Mike Graham

Comme d'autres l'ont dit, append mute la liste elle-même et vous ne devez pas l'affecter à une variable. L'exécuter change ses données, mettant à jour efficacement tous ceux qui les pointent.

Mais , il y a une astuce que j'utilise lorsque je veux faire des choses de manière fonctionnelle * tout en mutant les objets existants (plutôt que d'en construire de nouveaux, dans ce cas en utilisant a=[x + ['a'] for x in a], ou plus précisément le x + ['a']).

Donc, si vous êtes assez courageux, vous pouvez également le faire:

>>> a=[[1,2],[3,4],[5,6]]
>>> a=[x.append('a') or x for x in a]
>>> a
[[1, 2, 'a'], [3, 4, 'a'], [5, 6, 'a']]

Cela fonctionne parce que append renvoie None et que or continue de rechercher une valeur vérité-y, qui x est (c'est un list avec au moins ce qui y a été ajouté).

Pourquoi ai-je même besoin de cela?

Supposons que vous ayez une liste et que vous souhaitiez insérer certains de ses membres dans une nouvelle liste et mettre à jour les références en conséquence:

Vous avez donc la liste all:

>>> all = [[], [], [], []]

Une partie est insérée et mise à jour dans une nouvelle liste x:

>>> x = [i.append('x') or i for i in all[:2]]
>>> x
[['x'], ['x']]

Une partie de all est également insérée et mise à jour dans une liste y:

>>> y = [i.append('y') or i for i in all[1:3]]

all est mis à jour:

>>> all
[['x'], ['x', 'y'], ['y'], []]

Mais x est également mis à jour:

>>> x
[['x'], ['x', 'y']]

Et y est généré comme prévu:

>>> y
[['x', 'y'], ['y']]

Dans l'ensemble, pour des tâches simples, je recommanderais d'utiliser une mise à jour de boucle for explicitement. C'est ce qui est considéré comme Pythonic.

Techniquement parlant, si vous aviez accès à la classe list, vous pourriez en faire une fonction:

def more_functional_append(self, x):
    self.append(x)
    return self
  • programmation fonctionnelle est basé sur chaque déclaration faisant essentiellement une chose, et n'ayant pas d'effets secondaires (donc, pas de mutation et de retour). append n'est pas très fonctionnel car il mute une liste (la programmation fonctionnelle pure n'a que des objets immuables) et ne renvoie pas de résultat à passer à d'autres actions (fonctions). En utilisant des concepts de programmation fonctionnels, vous pouvez créer de superbes lignes simples que personne ne peut lire, également appelées "sécurité d'emploi" ou "mauvais code".
16
Reut Sharabani

Pour le premier cas, la raison pour laquelle il renvoie [None, None, None] est parce que le list.append la fonction renvoie None, et c'est ce qu'elle stocke dans la liste.

Dans le second cas, c'est parce que la liste est modifiable, et chaque fois que vous ajoutez la valeur, la liste d'origine est modifiée.

Vous avez besoin d'un opérateur d'ajout non en place, tel que +. c'est à dire. [x + ['a'] for x in a].

11
sykora

(Ceci est une combinaison des réponses de Mike Graham et sykora):

Si vous souhaitez simplement modifier les valeurs sur place, essayez une boucle for régulière et non une compréhension de liste:

for sublist in a:
    sublist.append('a')

Si vous voulez laisser un seul et mettre le résultat dans a1:

a1 = [sublist + ['a'] for sublist in a]

Comme ils l'ont expliqué, append modifie la liste, mais renvoie None, tandis que + laisse la liste seule, mais renvoie une nouvelle liste ajoutée.

4
Oddthinking

Vous pouvez utiliser l'ajout de liste dans une compréhension de liste, comme suit:

a = [x + ['a'] for x in a] 

Cela donne le résultat souhaité pour a. On pourrait le rendre plus efficace dans ce cas en affectant ['a'] à un nom de variable avant la boucle, mais cela dépend de ce que vous voulez faire.

2
Bud

quitter le a = et utilisez l'effet secondaire sur a:

[x.append('a') for x in a] 
print a
0
Ruggero Turra

Dans la première attribution de valeur de votre compréhension de liste, une erreur d'attribut, l'objet 'NoneType' n'a pas d'attribut 'append', aide à expliquer pourquoi votre liste, a, sera chargée avec None (s). Pour que ma console génère l'erreur, j'ai utilisé x comme variable pour la compréhension de la liste et également comme itérateur.

Traceback (most recent call last):
x = [x.append('a') for x in a]
AttributeError: 'NoneType' object has no attribute 'append'

Ensuite, je suis revenu à un pour x et cela a provoqué la même erreur.

Traceback (most recent call last):
a = [x.append('a') for x in a]
AttributeError: 'NoneType' object has no attribute 'append'
0
Rider