ジェネレーターのスタイルは、リストを返すよりも直接的である可能性があると何度も思いました。たとえば、
def foo(input_array):
for x in input_array:
yield processed(x)
vs.
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)
私の知る限りでは(そして、まったく同じことを考えていたので、私は調べました)、いいえ:標準ライブラリでこれを行う直接的な方法はありません。
ただし、unstdlib.pyライブラリには徹底的にテストされたlistify
ラッパーがあります: 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)
@David Woleverの答えは非常にクリーンな方法ですが、(外部デコレータを定義する必要がないため)私がよく行うことの1つは、ジェネレータをローカル関数として次のように記述することです。
def foo(input_array):
def gen():
for x in input_array:
yield processed(x)
return list(gen())
これは、ベルやホイッスルのない、代替のシンプルなデコレータです。
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