如何在 python lambda 中使用 await

新手上路,请多包涵

我正在尝试做这样的事情:

 mylist.sort(key=lambda x: await somefunction(x))

但我收到此错误:

 SyntaxError: 'await' outside async function

这是有道理的,因为 lambda 不是异步的。

我尝试使用 async lambda x: ... 但抛出一个 SyntaxError: invalid syntax

Pep 492 指出:

可以提供异步 lambda 函数的语法,但这种构造超出了本 PEP 的范围。

但我无法确定该语法是否在 CPython 中实现。

有没有办法声明异步 lambda,或使用异步函数对列表进行排序?

原文由 iCart 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.8k
2 个回答

你不能。没有 async lambda ,即使有,你也不能将它作为关键函数传递给 list.sort() ,因为关键函数将作为同步函数调用而不是等待.一个简单的解决方法是自己注释您的列表:

 mylist_annotated = [(await some_function(x), x) for x in mylist]
mylist_annotated.sort()
mylist = [x for key, x in mylist_annotated]

请注意 await 列表理解中的表达式仅在 Python 3.6+ 中受支持。如果您使用的是 3.5,则可以执行以下操作:

 mylist_annotated = []
for x in mylist:
    mylist_annotated.append((await some_function(x), x))
mylist_annotated.sort()
mylist = [x for key, x in mylist_annotated]

原文由 Sven Marnach 发布,翻译遵循 CC BY-SA 4.0 许可协议

An “ async lambda ” can be emulated by combining a lambda with an async generator: 1

 key=lambda x: (await somefunction(x) for _ in '_').__anext__()

可以将 ( ).__anext__() 移动到助手,这也可能使模式更清晰:

 def head(async_iterator): return async_iterator.__anext__()

key=lambda x: head(await somefunction(x) for _ in '_')

请注意,标准库中的排序方法/函数不是异步的。需要一个异步版本,例如 asyncstdlib.sorted (免责声明:我维护这个库):

 import asyncstdlib as a

mylist = await a.sorted(mylist, key=lambda x: head(await somefunction(x) for _ in '_'))


了解 lambda ...: (...).__anext__() 模式

async lambda ”将是一个匿名异步函数,或者换句话说,一个评估为可等待对象的匿名函数。这与 async def 如何定义评估为可等待的命名函数并行。

该任务可以分为两部分: 匿名函数表达式 和嵌套 _等待表达式_。

  • 匿名函数表达式正是 lambda ...: ... 的意思。

  • 等待表达式 只允许在协程函数中使用;然而:

    • 一个(异步)生成器表达式隐式地创建一个(协程)函数。由于异步生成器只需要异步运行,它可以在同步函数中 _定义_( 自 Python 3.7 起)。
    • 异步可迭代对象可以通过其 __anext__ 方法 用作可等待对象。

这三部分直接用在“ async lambda ”模式中:

 #   | regular lambda for the callable and scope
#   |         | async generator expression for an async scope
#   v         v                                    v first item as an awaitable
key=lambda x: (await somefunction(x) for _ in '_').__anext__()

异步生成器中的 for _ in '_' 只能进行一次迭代。任何至少有一次迭代的变体都可以。


1请注意“ async lambda ”是否真的首先需要,因为异步函数就像常规函数一样是一流的。 Just as lambda x: foo(x) is redundant and should just be foo , lambda x: (await bar(x) …) is redundant and should just be bar .函数体应该做的不仅仅是调用和 await ,例如 3 + await bar(x)await bar(x) or await qux(x)

原文由 MisterMiyagi 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题