我发现基于yield
的生成器对于过于复杂而无法使用列表推导的序列操作非常有用。假设我想从专门的生成器构造一个列表。我可以这样写:
def gen():
for <whatever>:
yield x
xs = list(gen())
很多时候,我只需要评估一次这个生成器,所以它并不需要一个名字。如果Python有多行labmdas,我可以使用:
xs = list((lambda:
for <whatever>:
yield x)())
但Python并没有多行lambda。有没有其他方法可以得到这样的东西?
(注意:请不要建议使用列表推导;我正在讨论何时yield
的逻辑更复杂的情况。)
答案 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中的块,可以使用这样的装饰器来完成。