один лайнер для итерации (генератор)

Я наткнулся на код вроде:

[func(val) for val in iterable]

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

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

Если возвращаемое значение func всегда оценивает False, то следующие работы:

any(func(val) for val in iterable)

Если возвращаемое значение func всегда оценивается как True, то следующие работы:

all(func(val) for val in iterable)

Что мне делать, если возвращаемое значение func может оцениваться как True или чтобы False

Что может быть лучше, чем установить значение False?

Лучшее, что я придумал:

any(func(val) and False for val in iterable)

или

all(func(val) or True for val in iterable)

3 ответа

Решение

Наверное просто

for val in iterable:
   func(val)

самый ясный.

for val in iterable: func(val)

доступен, если действительно необходим однострочный.

Как насчет использования set с участием bool функция?

{bool(func(val)) for val in iterable}

РЕДАКТИРОВАТЬ:
Посмотрев на анализ @gelonida, я считаю, что следующее немного быстрее.

{None for val in iterable(N) if func(val)}

Просто синтез и временной анализ предоставленных ответов / возможных решений

Кажется, что ответ @LeopardShark - самый короткий и самый читаемый ответ. и среди самых быстрых. (время неточно и я не смотрел байтовые коды)

Мудрая скорость - ответ @LeopardShark - второе предложение @ywbaek - исходный код, который я нашел, если N не слишком велик (~10000) - предложения, которые я опубликовал в своем вопросе

У исходного кода есть недостаток в том, что освобождение памяти выделяется даром.

Код, который я предложил в своем вопросе, имеет недостаток, заключающийся в том, что он менее интуитивно понятен, и если он испортил комбинацию (all, any) а также (and False, or True) можно не выполнить все, как ожидалось, а также он будет немного менее производительным

Решение @ywbaek безопаснее, чем мои предложения, и примерно такое же интуитивно понятное, но выполняется немного быстрее.

У простейшего решения есть небольшой недостаток: его нельзя использовать в качестве лямбды.

Мой код для расчета времени:

N=10000
M=500

called = 0
def func(v):
    global called
    called += 1
    v * v * v * v * v *v / (v+0.1)

def iterable(N):
    for v in range(N):
        v * 2
        yield v

def testrun():
    global called
    called=0
    print(timeit(test, number=M), end=" ")
    print(called)

print("consume some CPU")
timeit(lambda: 3**.5 **.2) # it seems, that timeit is a little more predictable if I let the process warm up a little

print("Start measures")

def test():
    for val in iterable(N): func(val)
testrun()

def test():
    {None for val in iterable(N) if func(val)}
testrun()

def test():
    [func(val) for val in iterable(N)]
testrun()

def test():
    all(func(val) or True for val in iterable(N))
testrun()

def test():
    any(func(val) and False for val in iterable(N))
testrun()

результаты на моем старом ПК:

consume some CPU
Start measures
3.864932143012993 5000000
3.916696268017404 5000000
4.0817033689818345 5000000
4.293206526956055 5000000
4.319622751965653 5000000

Другие вопросы по тегам