Ответ 1
Это очень анти-Pythonic, и любой опытный Pythonista даст вам черт возьми. Промежуточный список отбрасывается после его создания, и он потенциально может быть очень, очень большим и, следовательно, дорогостоящим для создания.
Подумайте о функции, которую я вызываю для нее побочные эффекты, а не возвращают значения (например, печать на экран, обновление GUI, печать в файл и т.д.).
def fun_with_side_effects(x):
...side effects...
return y
Теперь, это Pythonic, чтобы использовать списки, чтобы вызвать этот func:
[fun_with_side_effects(x) for x in y if (...conditions...)]
Обратите внимание, что я не сохраняю список в любом месте
Или мне следует называть это func следующим образом:
for x in y:
if (...conditions...):
fun_with_side_effects(x)
Что лучше и почему?
Это очень анти-Pythonic, и любой опытный Pythonista даст вам черт возьми. Промежуточный список отбрасывается после его создания, и он потенциально может быть очень, очень большим и, следовательно, дорогостоящим для создания.
Вы не должны использовать понимание списка, потому что, как сказали люди, вы создадите большой временный список, который вам не нужен. Следующие два метода эквивалентны:
consume(side_effects(x) for x in xs)
for x in xs:
side_effects(x)
с определением consume
на странице itertools
man:
def consume(iterator, n=None):
"Advance the iterator n-steps ahead. If n is none, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
Конечно, последнее понятно и понятнее.
Смысл списка заключается в создании списков. И если вы на самом деле не создаете список, вы не должны использовать списки.
Итак, я получил бы второй вариант, просто перейдя по списку, а затем вызовет функцию, когда применяются условия.
Во-вторых, лучше.
Подумайте о человеке, который должен понимать ваш код. Вы можете получить плохую карму легко с первой:)
Вы можете пойти посредине между ними, используя filter(). Рассмотрим пример:
y=[1,2,3,4,5,6]
def func(x):
print "call with %r"%x
for x in filter(lambda x: x>3, y):
func(x)
Зависит от вашей цели.
Если вы пытаетесь выполнить некоторую операцию над каждым объектом в списке, необходимо принять второй подход.
Если вы пытаетесь создать список из другого списка, вы можете использовать понимание списка.
Явный лучше, чем неявный. Простой лучше, чем сложный. (Python Zen)
Вы можете сделать
for z in (fun_with_side_effects(x) for x in y if (...conditions...)): pass
но это не очень красиво.
Я бы сделал это вместо этого:
any(fun_with_side_effects(x) and False for x in y if (...conditions...))
Это выражение генератора и не генерирует случайный список, который отбрасывается. Я думаю, что это уродливо, и я бы не делал этого в коде. Но если вы настаиваете на том, чтобы реализовать свои циклы таким образом, как бы я это сделал.
Я склонен чувствовать, что понимание списков и их образ должны сигнализировать о попытке использовать что-то, по крайней мере слабо напоминающее функциональный стиль. Помещение вещей с побочными эффектами, которые нарушают это предположение, заставит людей читать ваш код более тщательно, и я думаю, что это плохо.