为什么 Python 中存在这种涉及异步的奇怪语法?

Why does this weird syntax oddity involving async exist in Python?

我在文件中有这么一小段代码 (small.py):

def async(foo):
    pass

def bar(foo):
    pass

async def bar(foo):
    return None

async def async(foo):
    return None

当我这样做时 python3.6 small.py 它发出了这个投诉:

  File "small.py", line 7
    async def async(foo):
                  ^
SyntaxError: invalid syntax

如果我注释掉文件的最后两行,它就可以正常工作。

这是怎么回事?为什么 def async 完全没问题,但 async def async 却不行?

另外,我有这个文件 (small2.py):

def async(foo):
    pass

def bar(foo):
    return async(foo)

async def baz(foo):
    return async(foo)

当我这样做时 python2.6 small2.py 我得到了这个:

  File "small2.py", line 8
    return async(foo)
               ^

但是,如果我将 baz 更改为调用 bar 而不是 async,它就可以正常工作。如何在 baz 中调用 async

错误的原因是您使用保留关键字 async 作为您的函数名称,因此无论何时您尝试调用它。它尝试调用 async 关键字而不是被相同关键字覆盖的函数。

为了在一个目录中更清楚地演示这一点,创建两个文件,一个名称为 requests.py,另一个名称为 test.py. 现在,如果您使用 import requests(python library) 并使用test.py 中的任何方法都会抛出错误。因为文件 requests.py 覆盖了库 requests

同样的场景也发生在这里。您已经声明了一个名称为 async 的函数。此外,您稍后还声明了一个异步方法,该方法覆盖了名称为 async 的方法。因此,每当您调用异步时,它都会尝试调用异步方法。由于 async 保留关键字 并且不再是已被覆盖的函数,因此它会报告错误。要解决此问题,请将函数名称从 async 更改为其他名称。

'''def async(foo): #overrides async coroutine hence now async refers to this function.
    pass'''

def asyn(foo):
     pass

def bar(foo):
    pass

async def bar(foo):
    return None

async def asyn(foo): # aync refers to above commented method in your code rather than coroutine.
    return None

您问题的后一种情况也是如此。

好吧,我希望有人能回答这个问题,但没有人给出正确答案。

问题是在Python 3.5 和3.6 中,单词asyncawait 是关键字,但只是有时。其他时候他们扮演标识符的角色。

唯一一次 await 是关键字是在声明的函数内部 async def。唯一一次 async 是关键字是在 def 之前或 async def 函数内部。当然,在 async def async(foo) 的情况下, async 的第二次使用是试图将它用作 async def 内的标识符,因此它失败了,因为它是一个关键字。

这有点奇怪,因为所有其他关键字在任何地方都是关键字。例如,您永远不能使用 while 作为标识符。

这种情况将在 Python 3.7 中改变,asyncawait 都将成为关键字,就像其他关键字一样。

在 Python 3.5 和 3.6 中是这样的,因为他们不想 spring 立即为每个人添加一个新关键字。当你添加一个新的关键字时,很多人可能拥有与你的新关键字同名的标识符,因此这些标识符变得非法,人们不得不更改他们的代码并且可能会遇到各种奇怪的错误,直到他们这样做。

关于如何在 async def 函数中使用名为 asyncawait 的标识符的答案是你不需要。您必须使用 getattr 或别名标识符所指的对象或以其他方式安排它,这样您就不会在 async def 函数中使用单词 asyncawait 作为任何东西除了关键字它们都在那里。

这在 transition plan section of PEP 492.

中进行了一些描述,但其中的含义并未真正彻底解决

附带说明一下,在 Python 中重新定义名称就可以了。最好将 def foo 视为 foo = lambda(除了 lambda 仅限于 Python 中的单个表达式)。因此,将新函数值分配给 foo 不会导致任何问题,而且简单且定义明确。