用于从匿名生成器

时间:2018-05-05 03:45:05

标签: python generator anonymous-function

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

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

xs = list(gen())

很多时候,我只需要评估一次这个生成器,所以它并不需要一个名字。如果Python有多行labmdas,我可以使用:

xs = list((lambda:
    for <whatever>:
        yield x)())

但Python并没有多行lambda。有没有其他方法可以得到这样的东西?

(注意:请不要建议使用列表推导;我正在讨论何时yield的逻辑更复杂的情况。)

2 个答案:

答案 0 :(得分:0)

如果逻辑对于生成器表达式来说过于复杂,那么您可能不应该使用lambda。这与说不出你的行为不一样。

Python lambdas可以拥有任意数量的换行符。它们只是不能包含语句,只能包含表达式。您可以在lambda中使用yield 表达式(而非yield语句 - 您需要额外的括号。

>>> list((lambda: (yield 1))())
[1]

没那么有用,是吗?您可以使用... a list display expression - []执行yield表达式列表。 (Python保证按顺序评估显示元素。)

>>> tuple((lambda:[
    (yield 1),
    (yield 2),
    (yield 3),
])())
(1, 2, 3)

元组也有效。看那个。多条&#34;线&#34; (不是陈述)。仍然没那么有用。你希望能够循环。但是for声明是一个声明。 (同样,为什么不使用生成器expresson?那些表达式。)实际上,这不是限制,因为lambdas可以调用包含语句的函数。

>>> 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更容易阅读。您可以给它一个短暂的一次性名称,例如_f或其他。

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

这意味着我们在技术上甚至不需要loop功能。您可以改为使用递归。 (虽然在Python中,你最终会获得Stack Overflow。)但是你如何在一个匿名函数上进行递归?

你使用&#34;装饰&#34;给它一个名字。

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

当然,&#34;装饰&#34;也可以是匿名的。

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

我一开始并没有这样写,因为看到太多的lambdas,你的眼睛会茫然。这就是你应该使用def

的原因

如果您对我们可以推送这样的lambdas感兴趣,请查看Drython,其中每个Python语句都有类似的表达式替换。

答案 1 :(得分:0)

装饰者不拥有来返回一个函数。

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]

在大多数情况下,rubyist需要Python中的块,可以使用这样的装饰器来完成。