Является ли Pythonic использовать списочные выражения только для побочных эффектов? - PullRequest
92 голосов
/ 22 апреля 2011

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

def fun_with_side_effects(x):
    ...side effects...
    return y

Теперь Pythonic использует списочные выражения для вызова этой функции:

[fun_with_side_effects(x) for x in y if (...conditions...)]

Обратите внимание, что я нигде не сохраняю список

Или я должен назвать этот функционал так:

for x in y:
    if (...conditions...):
        fun_with_side_effects(x)

Что лучше и почему?

Ответы [ 7 ]

74 голосов
/ 22 апреля 2011

Это очень анти-Pythonic, чтобы сделать это, и любой опытный Pythonista даст вам ад из-за этого.Промежуточный список выбрасывается после его создания, и он потенциально может быть очень, очень большим и, следовательно, дорогим для создания.

28 голосов
/ 22 апреля 2011

Вы не должны использовать список понимания, потому что, как говорили люди, это создаст большой временный список, который вам не нужен.Следующие два метода эквивалентны:

consume(side_effects(x) for x in xs)

for x in xs:
    side_effects(x)

с определением consume из справочной страницы itertools:

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)

Конечно, последний яснее и легчепонимать.

20 голосов
/ 22 апреля 2011

Списочные выражения предназначены для создания списков. И если вы на самом деле не создаете список, вы должны не использовать списочные выражения.

Таким образом, я бы выбрал второй вариант, просто перебирая список и затем вызывая функцию, когда применяются условия.

11 голосов
/ 22 апреля 2011

Секунда лучше.

Подумайте о человеке, который должен понимать ваш код. Вы можете легко получить плохую карму с первым:)

Вы можете пойти посередине между ними, используя 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)
3 голосов
/ 22 апреля 2011

Зависит от вашей цели.

Если вы пытаетесь выполнить какую-либо операцию с каждым объектом в списке, следует принять второй подход.

Если вы пытаетесь создать список из другого списка, вы можете использовать его понимание.

Явное лучше, чем неявное. Простое лучше, чем сложное. (Python Zen)

1 голос
/ 22 апреля 2011

Вы можете сделать

for z in (fun_with_side_effects(x) for x in y if (...conditions...)): pass

, но это не очень красиво.

0 голосов
/ 22 апреля 2011

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

Но, если вы абсолютно настаиваете на использовании понимания списка для его побочных эффектов, вам следует избегать неэффективности, используя вместо этого выражение-генератор. Если вы абсолютно настаиваете на этом стиле, выполните одно из следующих действий:

any(fun_with_side_effects(x) and False for x in y if (...conditions...))

или

all(fun_with_side_effects(x) or True for x in y if (...conditions...))

Это выражения-генераторы, и они не генерируют случайный список, который отбрасывается. Я думаю, что форма all, возможно, немного более понятна, хотя я думаю, что они оба сбивают с толку и не должны использоваться.

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

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

...