Когда выпадать из списка "Понимание" и "Pythonic way"?

Я создал строку, которая добавляет объект в список следующим образом

>>> foo = list()
>>> def sum(a, b):
...      c = a+b; return c
...
>>> bar_list = [9,8,7,6,5,4,3,2,1,0]
>>> [foo.append(sum(i,x)) for i, x in enumerate(bar_list)]
[None, None, None, None, None, None, None, None, None, None]
>>> foo
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
>>>

Линия

[foo.append(sum(i,x)) for i, x in enumerate(bar_list)]

дал бы указание W1060 Выражение не назначено ни к чему, но так как я уже использую список foo, чтобы добавить значения, мне не нужно добавлять строку со списком к чему-либо.

Мои вопросы больше связаны с правильностью программирования

Должен ли я отбросить понимание списка и просто использовать простое выражение?

>>> for i, x in enumerate(bar_list):
...      foo.append(sum(i,x))

или есть правильный способ использовать оба списка понимания присвоения ни к чему?

Ответ

Спасибо @user2387370, @kindall и @Martijn Pieters. Для остальных комментариев я использую append, потому что я не использую list(), я не использую i+x, потому что это просто упрощенный пример.

Я оставил это как следующее:

histogramsCtr = hist_impl.HistogramsContainer()
for index, tupl in enumerate(local_ranges_per_histogram_list):
    histogramsCtr.append(doSubHistogramData(index, tupl))
return histogramsCtr

3 ответа

Решение

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

Почему бы не определить foo используя понимание списка в первую очередь?

foo = [sum(i,x) for i, x in enumerate(bar_list)]

Если это не список, а какой-то другой контейнерный класс, как вы упомянули в комментарии к другому ответу, напишите этот класс, чтобы он принимал итератор в своем конструкторе (или, если это не ваш код, для этого сделайте его подклассом), затем передайте ему выражение генератора:

foo = MyContainer(sum(i, x) for i, x in enumerate(bar_list))

Если foo уже имеет какое-то значение, и вы хотите добавить новые элементы:

foo.extend(sum(i,x) for i, x in enumerate(bar_list))

Если вы действительно хотите использовать append() и не хочу использовать for цикл по какой-то причине, то вы можете использовать эту конструкцию; выражение генератора, по крайней мере, позволит избежать бесполезной траты памяти и циклов ЦП в списке, который вам не нужен:

any(foo.append(sum(i, x)) for i, x in enumerate(bar_list))

Но это гораздо менее понятно, чем обычный for цикл, и есть еще некоторая дополнительная работа: any проверяет возвращаемое значение foo.append() на каждой итерации. Вы можете написать функцию для использования итератора и исключить эту проверку; самый быстрый способ использует нулевую длину collections.deque:

from collections import deque
do = deque([], maxlen=0).extend

do(foo.append(sum(i, x)) for i, x in enumerate(bar_list))

Это на самом деле довольно читабельно, но я считаю, что на самом деле это не так быстро, как any() и требует дополнительного импорта. Однако либо do() или же any() немного быстрее, чем for цикл, если это проблема.

Я думаю, что обычно не одобряется использование списочных представлений только для побочных эффектов, поэтому я бы сказал, что цикл for лучше в этом случае.

Но в любом случае, вы не могли бы просто сделать foo = [sum(i,x) for i, x in enumerate(bar_list)]?

Вы должны определенно отказаться от понимания списка. Конец чего-либо.

  • Вы путаете любого, кто читает ваш код. Вы строите список побочных эффектов.
  • Вы платите циклы процессора и память за создание списка, который вы снова удаляете.

В вашем упрощенном случае вы упускаете из виду тот факт, что могли бы использовать непосредственное использование списка:

[sum(i,x) for i, x in enumerate(bar_list)]
Другие вопросы по тегам