简体   繁体   中英

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

I have this small bit of code in a file ( small.py ):

def async(foo):
    pass

def bar(foo):
    pass

async def bar(foo):
    return None

async def async(foo):
    return None

When I do python3.6 small.py it issues this complaint:

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

If I comment out the last two lines of the file it works fine.

What's going on here? Why is it perfectly fine to have def async but not OK to have async def async ?

Additionally, I have this file ( small2.py ):

def async(foo):
    pass

def bar(foo):
    return async(foo)

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

And when I do python2.6 small2.py I get this:

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

But if I change baz to call bar instead of async it works just fine. How do I call async inside of baz ?

Well, I was hoping someone would answer this, but nobody has with the correct answer.

The problem is that in Python 3.5 and 3.6, the words async and await are keywords, but only sometimes. Other times they play the role of identifiers.

The only time await is a keyword is inside of a function declared async def . And the only time async is a keyword is just before def or inside an async def function. Of course, in the async def async(foo) case, the second use of async is an attempt to use it as an identifier inside an async def and so it fails because there, it's a keyword.

This is kind of weird, as all other keywords are always keywords everywhere. For example, you can't use while as an identifier ever.

This situation will change in Python 3.7 and both async and await will be keywords everywhere, just like every other keyword.

It's this way in Python 3.5 and 3.6 because they didn't want to just spring a new keyword on everybody right away. When you add a new keyword, lots of people might have identifiers that have the same name as your new keyword, and so those identifiers become illegal and people have to change their code and may get all kinds of weird errors until they do.

The answer to how to use an identifier named async or await inside of an async def function is that you don't. You have to use getattr or alias the object the identifier refers to or otherwise arrange it so that you do not use the words async or await in your async def function as anything other than the keywords they are there.

This is described a little, though the implications are not really thoroughly worked through, in the transition plan section of PEP 492 .

As a side note, redefining names in Python is just fine. One might better think of def foo as foo = lambda (except that lambdas are limited to single expressions in Python). So, assigning a new function value to foo causes no problems and is simple and well defined.

The reason for the error is you are using the reserved keyword async as your function name so when ever you try to invoke it. It tries to call the async keyword rather than the function which has been overridden by the same.

To demonstrate this more clearly in a directory create two files one with name requests.py another one as test.py. Now if you use import requests ( python library ) and use any of it's methods in test.py it ll throw you an error. Because the file requests.py overrides the library requests .

The same scenario happens here. You have declared a function with name async . Also you have declared a async method later which overrides the method with name async . Hence whenever you call async it tries to call async method. Since async is a reserved keyword and no longer a function which has been overridden, it reports error. To fix this change the function name from async to something else.

'''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

Also the same happens with the later case of your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM