从匿名生成器构造列表的Python习惯用法

从匿名生成器构造列表的Python习惯用法,python,generator,anonymous-function,Python,Generator,Anonymous Function,我发现基于yield的生成器对于过于复杂而无法使用列表理解的序列操作非常有用。假设我想从一个专门的生成器构造一个列表。我可以这样写: def gen(): for <whatever>: yield x xs = list(gen()) def gen(): 用于: 产量x xs=列表(gen()) 很多时候,我只需要对这个生成器求值一次,所以它实际上不需要名称。如果Python有多行LabMDA,我可以使用: xs = list((lambda:

我发现基于
yield
的生成器对于过于复杂而无法使用列表理解的序列操作非常有用。假设我想从一个专门的生成器构造一个列表。我可以这样写:

def gen():
    for <whatever>:
        yield x

xs = list(gen())
def gen():
用于:
产量x
xs=列表(gen())
很多时候,我只需要对这个生成器求值一次,所以它实际上不需要名称。如果Python有多行LabMDA,我可以使用:

xs = list((lambda:
    for <whatever>:
        yield x)())
xs=list((λ:
用于:
收益率(x)()
但是Python没有多行lambda。有没有别的办法得到这样的东西


(注意:请不要建议使用列表理解;我指的是when to
yield
的逻辑更复杂的情况。)

如果逻辑对于生成器表达式来说太复杂,您可能不应该使用lambda。这和说你不能一样

Python lambda可以有任意多的新行。它们不能包含语句,只能包含表达式。您可以在lambda中使用
yield
表达式(而不是
yield
语句——您需要额外的括号)

>>> list((lambda: (yield 1))())
[1]
没那么有用吧?您可以使用--<代码>[]。(Python保证按顺序计算显示元素。)

元组也起作用。看那个。多行(非语句)。还是没那么有用。您希望能够循环。但是
for
语句是一个语句。(同样,为什么不使用generator expresson?这些都是表达式。)实际上,这并没有限制,因为lambda可以调用包含语句的函数

>>> def loop(itr, body):
    for x in itr:
        yield body(x)


>>> list(loop(range(9), lambda x: x*x))
[0, 1, 4, 9, 16, 25, 36, 49, 64]
这就是在不使用理解的情况下创建for循环的方法。但是我们想要在lambda中的循环

>>> list((lambda:
      (yield from loop(range(9), lambda x:
               x*x))
      )())
[0, 1, 4, 9, 16, 25, 36, 49, 64]
是的,
yield from
也是一个表达式。如果用括号括起来。我认为缩进很好的
def
s更容易阅读。你可以给它一个简短的一次性名称,比如
\u f
或其他什么


lambda演算本身就是图灵完备的,能够计算任何可计算的东西

这意味着我们在技术上甚至不需要
循环
函数。您可以改用递归。(虽然在Python中,最终会出现堆栈溢出。)但是如何在匿名函数上递归呢

你用“装饰者”来给它起个名字

>>> def recur(func):
    def wrapper(*args, **kwargs):
        return func(func, *args, **kwargs)
    return wrapper

>>> tuple(recur(lambda r, n:[
    (yield n),
    (yield from r(r, n-1)) if n else 0]
     )(3))
(3, 2, 1, 0)
当然,“装饰者”也可以是匿名的

>>> tuple((lambda f: lambda *a, **kw: f(f, *a, **kw))(lambda r, n:[
    (yield n),
    (yield from r(r, n-1)) if n else 0]
     )(3))
(3, 2, 1, 0)
我不是这样写的,因为你的眼睛会因为看到太多的羔羊而变得呆滞。这就是为什么您应该使用
def

如果您想知道我们可以将lambda这样推到什么程度,请查看,它对每个Python语句都有类似的表达式替换。

装饰器不必返回函数

def genlist(g):
    return list(g())


@genlist
def xs():  # for <whatever>
    for x in range(3):
        yield x*x
    for x in range(3):
        yield x+x
    yield 42


print(xs)

在大多数情况下,rubyist需要Python中的一个块,这可以通过这样的修饰符来完成。

您可以编写一个生成器表达式
(范围(5)中的x代表x))
看起来像一个列表,但它是一个生成器,因为它位于
()
我看不出您的第一种方法或使用列表理解有任何错误,
[f(x)for x in container]
其中
f(x)
实现了
gen()中的逻辑。
听起来您对生成器函数的唯一异议是它有一个名称。为什么呢?你想解决什么问题?
def genlist(g):
    return list(g())


@genlist
def xs():  # for <whatever>
    for x in range(3):
        yield x*x
    for x in range(3):
        yield x+x
    yield 42


print(xs)
[0, 1, 4, 0, 2, 4, 42]