为什么 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 中,单词async
和await
是关键字,但只是有时。其他时候他们扮演标识符的角色。
唯一一次 await
是关键字是在声明的函数内部 async def
。唯一一次 async
是关键字是在 def
之前或 async def
函数内部。当然,在 async def async(foo)
的情况下, async
的第二次使用是试图将它用作 async def
内的标识符,因此它失败了,因为它是一个关键字。
这有点奇怪,因为所有其他关键字在任何地方都是关键字。例如,您永远不能使用 while
作为标识符。
这种情况将在 Python 3.7 中改变,async
和 await
都将成为关键字,就像其他关键字一样。
在 Python 3.5 和 3.6 中是这样的,因为他们不想 spring 立即为每个人添加一个新关键字。当你添加一个新的关键字时,很多人可能拥有与你的新关键字同名的标识符,因此这些标识符变得非法,人们不得不更改他们的代码并且可能会遇到各种奇怪的错误,直到他们这样做。
关于如何在 async def
函数中使用名为 async
或 await
的标识符的答案是你不需要。您必须使用 getattr
或别名标识符所指的对象或以其他方式安排它,这样您就不会在 async def
函数中使用单词 async
或 await
作为任何东西除了关键字它们都在那里。
这在 transition plan section of PEP 492.
中进行了一些描述,但其中的含义并未真正彻底解决
附带说明一下,在 Python 中重新定义名称就可以了。最好将 def foo
视为 foo = lambda
(除了 lambda 仅限于 Python 中的单个表达式)。因此,将新函数值分配给 foo
不会导致任何问题,而且简单且定义明确。
我在文件中有这么一小段代码 (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 中,单词async
和await
是关键字,但只是有时。其他时候他们扮演标识符的角色。
唯一一次 await
是关键字是在声明的函数内部 async def
。唯一一次 async
是关键字是在 def
之前或 async def
函数内部。当然,在 async def async(foo)
的情况下, async
的第二次使用是试图将它用作 async def
内的标识符,因此它失败了,因为它是一个关键字。
这有点奇怪,因为所有其他关键字在任何地方都是关键字。例如,您永远不能使用 while
作为标识符。
这种情况将在 Python 3.7 中改变,async
和 await
都将成为关键字,就像其他关键字一样。
在 Python 3.5 和 3.6 中是这样的,因为他们不想 spring 立即为每个人添加一个新关键字。当你添加一个新的关键字时,很多人可能拥有与你的新关键字同名的标识符,因此这些标识符变得非法,人们不得不更改他们的代码并且可能会遇到各种奇怪的错误,直到他们这样做。
关于如何在 async def
函数中使用名为 async
或 await
的标识符的答案是你不需要。您必须使用 getattr
或别名标识符所指的对象或以其他方式安排它,这样您就不会在 async def
函数中使用单词 async
或 await
作为任何东西除了关键字它们都在那里。
这在 transition plan section of PEP 492.
中进行了一些描述,但其中的含义并未真正彻底解决附带说明一下,在 Python 中重新定义名称就可以了。最好将 def foo
视为 foo = lambda
(除了 lambda 仅限于 Python 中的单个表达式)。因此,将新函数值分配给 foo
不会导致任何问题,而且简单且定义明确。