Когда выпадать из списка "Понимание" и "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)]