Есть ли библиотечная функция в Python, чтобы превратить функцию-генератор в функцию, возвращающую список?
Несколько раз я думал, что стиль генератора может быть более прямым, возвращая список, например
def foo(input_array):
for x in input_array:
yield processed(x)
против.
def bar(input_array):
accumulator = []
for x in input_array:
accumulator.append(processed(x))
return accumulator
(хорошо, если бы все было так просто, я бы написал map
, но вы поняли: версия генератора чиста). Однако тип возврата генератора не всегда желателен. Есть ли встроенный декоратор, который я могу использовать для изменения foo
в функцию, возвращающую список или кортеж? Как я сам напишу,
import functools
def transform_return_value(transformer):
def inner(f):
@functools.wraps(f)
def new_f(*argv, **kwargs):
return transformer(f(*argv, **kwargs))
return new_f
return inner
@transform_return_value(list)
def foo(input_array):
for x in input_array:
yield processed(x)
Ответы
Ответ 1
Насколько я знаю (и я посмотрел, потому что я задавался вопросом точно так же), нет: нет прямого способа сделать это со стандартной библиотекой.
Существует тщательно протестированная оболочка listify
в библиотеке undlib.py, но: https://github.com/shazow/unstdlib.py/blob/master/unstdlib/standard/list_.py#L149
def listify(fn=None, wrapper=list):
"""
A decorator which wraps a function return value in ``list(...)``.
Useful when an algorithm can be expressed more cleanly as a generator but
the function should return an list.
Example::
>>> @listify
... def get_lengths(iterable):
... for i in iterable:
... yield len(i)
>>> get_lengths(["spam", "eggs"])
[4, 4]
>>>
>>> @listify(wrapper=tuple)
... def get_lengths_tuple(iterable):
... for i in iterable:
... yield len(i)
>>> get_lengths_tuple(["foo", "bar"])
(3, 3)
"""
def listify_return(fn):
@wraps(fn)
def listify_helper(*args, **kw):
return wrapper(fn(*args, **kw))
return listify_helper
if fn is None:
return listify_return
return listify_return(fn)
Ответ 2
Несмотря на то, что ответ @David Wolever является самым суровым способом, одна вещь, которую я часто нахожу (поскольку она не требует определения внешнего декоратора), пишет генератор как локальную функцию, например:
def foo(input_array):
def gen():
for x in input_array:
yield processed(x)
return list(gen())
Ответ 3
Для эффективных и сжатых определений списков попробуйте использовать понимание списка:
def foo(input_array):
return [processed(x) for x in input_array]
Если вы хотите, чтобы функция возвращала список, верните список. Это намного чище, проще понять, прочитать и отладить, чем использовать декоратор.
Возможно, вы захотите написать эту встроенную строку, а не вызвать функцию.