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

时间:2017-06-11 16:20:19

标签: python asynchronous syntax python-3.5 python-3.6

我在文件(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,那就可以了。如何在async内拨打baz

2 个答案:

答案 0 :(得分:3)

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

问题是在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中就是这样,因为他们不想立刻在每个人身上弹出一个新关键字。当您添加新关键字时,很多人可能拥有与新关键字同名的标识符,因此这些标识符变为非法,人们必须更改其代码,并且可能会遇到各种奇怪的错误。

如何在async函数中使用名为awaitasync def的标识符的答案是您没有。您必须使用getattr或别名标识符引用的对象或以其他方式对其进行排列,以便您不会将async函数中的awaitasync def用作任何内容除了他们在那里的关键词。

虽然transition plan section of PEP 492中的含义并未真正彻底解决,但有一点描述。

作为旁注,在Python中重新定义名称就好了。人们可能最好将def foo视为foo = lambda(除了lambdas仅限于Python中的单个表达式)。因此,为foo分配一个新的函数值不会导致任何问题,并且简单且定义明确。

答案 1 :(得分:1)

错误的原因是您使用保留关键字async作为您的函数名称,所以当您尝试调用它时。它尝试调用async关键字而不是被同一关键字覆盖的函数。

要在目录中更清楚地展示这一点,请创建两个名为requests.py的文件,另一个文件为test.py.现在,如果您使用import requestspython library)并使用任何它在test.py中的方法会给你一个错误。因为文件requests.py会覆盖库requests

这里发生了同样的情况。您已声明名为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

在你的问题的后一种情况下也会发生同样的情况。