从匿名生成器构造列表的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]