Подтвердить что ты не робот

Есть ли библиотечная функция в 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)
4b9b3361

Ответ 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]

Если вы хотите, чтобы функция возвращала список, верните список. Это намного чище, проще понять, прочитать и отладить, чем использовать декоратор.

Возможно, вы захотите написать эту встроенную строку, а не вызвать функцию.