Добавление элемента в списки в пределах понимания списка - PullRequest
18 голосов
/ 24 марта 2010

У меня есть список, скажем, a = [[1,2],[3,4],[5,6]]

Я хочу добавить строку 'a' к каждому элементу в списке a.

Когда я использую:

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

возвращает [None,None,None].

Но если я использую:

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

тогда он делает что-то странное.

a, но не a1 - это [[1,2,'a'],[3,4,'a'],[5,6,'a']].

Я не понимаю, почему первый вызов возвращает [None, None, None] и почему второй меняется на a вместо a1.

Ответы [ 7 ]

29 голосов
/ 24 марта 2010

list.append изменяет сам список и возвращает None. Компоненты списков предназначены для сохранения результата, что в данном случае не то, что вам нужно, если вы хотите просто изменить исходные списки.

>>> x = [[1, 2], [3, 4], [5, 6]]
>>> for sublist in x:
...     sublist.append('a')
...
>>> x
[[1, 2, 'a'], [3, 4, 'a'], [5, 6, 'a']]
14 голосов
/ 18 января 2015

Как уже говорили другие, append изменяет сам список, и вам не следует присваивать его переменной. Выполнение этого изменяет его данные, эффективно обновляя всех, указывающих на это.

Но , есть трюк, который я использую, когда я хочу делать вещи функциональным * способом, изменяя существующие объекты (вместо того, чтобы создавать новые, в этом случае используя a=[x + ['a'] for x in a], или, в частности, x + ['a']).

Итак, если вы достаточно смелы, вы также можете сделать это:

>>> 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']]

Это работает, потому что append возвращает None, а or продолжает поиск значения true-y, которое x равно (это list по крайней мере с что было добавлено к нему).

Зачем мне это нужно?

Допустим, у вас есть список, и вы хотите вставить некоторых его членов в новый список и соответствующим образом обновить ссылки:

Итак, у вас есть список all:

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

Некоторые из них вставлены и обновлены в новый список x:

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

Часть all также вставляется и обновляется в список y:

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

all обновлено:

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

Но x также обновляется:

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

И y генерируется как ожидалось:

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

В целом, для простых задач я бы рекомендовал явно использовать цикл for. Это то, что считается питоническим.

Технически говоря, если бы у вас был доступ к списку классов, вы могли бы сделать это функцией:

def more_functional_append(self, x):
    self.append(x)
    return self
  • функциональное программирование основано на каждом утверждении, делающем по существу одну вещь, и не имеющем побочных эффектов (то есть не мутирующем и не возвращающем). append не очень функциональный, поскольку он мутирует список (чисто функциональное программирование имеет только неизменяемые объекты) и не возвращает результат для передачи другим действиям (функциям). Используя концепцию функционального программирования, вы можете создавать большие однострочники, которые никто не может прочитать, также известные как «безопасность работы» или «плохой код».
9 голосов
/ 24 марта 2010

В первом случае причина, по которой он возвращает [None, None, None], заключается в том, что функция list.append возвращает None, и это то, что она сохраняет в списке.

Во втором случае это потому, что список изменчив, и каждый раз, когда вы добавляете значение, исходный список изменяется.

Вам нужен оператор добавления на месте, например +. т.е. [x + ['a'] for x in a].

4 голосов
/ 24 марта 2010

(Это комбинация ответов Майка Грэма и Сикора):

Если вы просто хотите изменить значения на месте, попробуйте обычный цикл for, а не понимание списка:

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

Если вы хотите оставить в покое, и поставить результат в a1:

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

Как они объяснили, append изменяет список, но возвращает None, а + оставляет список в покое, но возвращает новый добавленный список.

2 голосов
/ 29 августа 2017

Вы можете использовать добавление списка в пределах понимания списка, например:

a = [x + ['a'] для x в a]

Это дает желаемый результат для a. В этом случае можно повысить его эффективность, назначив ['a'] имени переменной перед циклом, но это зависит от того, что вы хотите сделать.

0 голосов
/ 02 марта 2018

В первом назначении значения вашего списка понимания Ошибка атрибута, объект 'NoneType' не имеет атрибута 'append', помогает объяснить, почему ваш список, a, будет загружен None (s). Чтобы заставить консоль выдавать ошибку, я использовал x в качестве переменной для понимания списка, а также в качестве итератора.

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

Затем я вернулся к a для x, и он выдал ту же ошибку.

Traceback (most recent call last):
a = [x.append('a') for x in a]
AttributeError: 'NoneType' object has no attribute 'append'
0 голосов
/ 24 марта 2010

оставьте a = и используйте побочный эффект на a:

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