首先,整理一下这一个章节的代码,这一章节的代码的排布我觉得有点问题,所以就就先整理一个完整的版本在这里。

import asyncio
import itertools

async def spin(msg: str) -> None:
    status = "" # just to suppress the repostUnboundVariable of pyright
    for char in itertools.cycle(R"\\|/-"):
        status = f"\\r{char} {msg}"
        print(status, flush=True, end="")
        try:
            await asyncio.sleep(0.1)
        except asyncio.CancelledError:
            break
    blanks = " " * len(status)
    print(f"\\r{blanks}\\r", end="") # 用等量的空格把原来的字符给覆盖掉

async def slow() -> int:
    await asyncio.sleep(3)
    return 42

def main() -> None:
    result = asyncio.run(supervisor())
    print(f"Answer: {result}")

async def supervisor() -> int:
    spinner = asyncio.create_task(spin("thinking!"))
    print(f"spinner object: {spinner}")
    result = await slow()
    spinner.cancel()
    return result

if __name__ == "__main__":
    main()

问题一,async 函数可以先使用再 def?

是可以的。可以看以下的测试代码,

def main() -> None:
    result = supervisor()
    print(f"Answer: {result}")

def supervisor() -> int:
    spinner = 12
    print(f"spinner object: {spinner}")
    return 3

if __name__ == "__main__":
    main()

运行结果如下,

spinner object: 12
Answer: 3

可以看到,如果实际调用的函数在其中所需要用到的函数,以及其中的函数所需要用到的函数中出现的函数在这最外层调用的函数之前被定义过了的话,那么,运行就不成问题。我以前似乎出现了误解,比如如下的代码,

def main() -> None:
    result = supervisor()
    print(f"Answer: {result}")

main()

def supervisor() -> int:
    spinner = 12
    print(f"spinner object: {spinner}")
    return 3

其运行结果如下,

Traceback (most recent call last):
  File "/home/fanyfull/edisk/pyCodes/fluentPython/ch19/draft/draft02.py", line 5
, in <module>
    main()
  File "/home/fanyfull/edisk/pyCodes/fluentPython/ch19/draft/draft02.py", line 2
, in main
    result = supervisor()
NameError: name 'supervisor' is not defined

在这里,就是不可以的。为什么呢?因为 main() 所需要用到的函数是在其下面才进行定义的。我曾经不知道在哪里似乎看到过,Python 的解释似乎会对代码进行两趟扫描,但是显然,它在这里并不起作用。

问题二,await 到底会阻塞什么东西?

await 阻塞的是 await 所在的函数。