32

很多时候我认为生成器样式可以比返回列表更直接,例如,

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)
4

4 回答 4

27

据我所知(我看过,因为我想知道完全相同的事情),不:没有直接的方法可以使用标准库执行此操作。

listify不过,在 unstdlib.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's 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)
于 2012-09-11T20:03:26.977 回答
7

尽管@David Wolever 的回答是最干净的方式,但我经常发现自己在做的一件事(因为它不需要定义外部装饰器)是将生成器编写为本地函数,如下所示:

def foo(input_array):
    def gen():
        for x in input_array:
            yield processed(x)

    return list(gen())
于 2015-04-27T08:40:31.243 回答
3

这是一个替代的,简单的装饰器,没有任何花里胡哨:

from functools import wraps
from types import GeneratorType

def listify(func):
    """decorator for making generator functions return a list instead"""
    @wraps(func)
    def new_func(*args, **kwargs):
        r = func(*args, **kwargs)
        if isinstance(r, GeneratorType):
            return list(r)
        else:
            return r
    return new_func
于 2018-05-02T10:18:32.167 回答
-5

要获得高效简洁的列表定义,请尝试使用列表推导:

def foo(input_array):
    return [processed(x) for x in input_array]

如果你想让一个函数返回一个列表,让它返回一个列表。这比使用装饰器更简洁、更易于理解、阅读和调试。

您可能更喜欢内联编写此代码,而不是调用函数。

于 2012-09-11T20:14:11.507 回答