Python async/awaitのエラーをシンプルに出す。


Pythonのasync/await。入門するとエラーがわかりづらい。

* SyntaxError: 'await' outside function
* RuntimeWarning: coroutine 'main' was never awaited
* TypeError: object async_generator can't be used in 'await' expression
* TypeError: object generator can't be used in 'await' expression
* await value ```<generator object 関数名 at アドレス>```がエターナル
* await value ```<async_generator object 関数名 at アドレス>```がエターナル
* TypeError: 'async_generator' object is not iterable
* TypeError: 'async for' requires an object with ```__aiter__``` method, got generator
* RuntimeWarning: coroutine 'sleep' was never awaited
* RuntimeError: Task got bad yield: 0

そこで上記の**エラーが出るシンプルなコード例**（エラーの出ない例も少し）を作ってみることにしました。 

この記事には、本質的な同期/非同期の話はありません。単にasync/await周りのエラーはこうすると出ますという、逆引き風の例です。

余談ですが、この例を作り終わったあと、昨晩ハマっていたいくつかのasync/await課題はコードを見ただけでウソのように直せるようになっていました。

# SyntaxError: 'await' outside function

構文エラーで、「"await" は非同期関数内でのみ許可されます」というPylanceのメッセージが出ます。

### エラー例１
```python
import asyncio


async def simple():
    return 49


await simple()
```

### エラー例2
```python
import asyncio


async def simple():
    return 49


def main():  # ★これが非同期関数ではない
    ret_value = await simple()
    print(f"await value {ret_value}")


main()
```

main（）をasync defにして実行すると次のRuntimeWarningが出ます。 asyncのコルーチンは関数のように呼び出しても実行されないのがPythonのasync/awaitのわかりにくいところですね。コルーチンを生成してくれるだけ（コンストラクタ）です。

# RuntimeWarning: coroutine 'main' was never awaited

これはワーニングが出る例ですが、プログラムとして実行もされません。

### ワーニング例
```python
import asyncio


async def simple():
    return 49

    
async def main():
    ret_value = await simple()
    print(f"await value {ret_value}")


main() # 非同期関数の呼び出しはコルーチンを生成するだけ、実行されない。
```

### 動く例
```python
import asyncio


async def simple():
    return 49


async def main():
    ret_value = await simple()
    print(f"await value {ret_value}")


asyncio.run(main()) # 非同期関数を実行する。
```

# TypeError: object async_generator can't be used in 'await' expression

### エラー例
```python
import asyncio


async def simple():  ## async付きでyieldする関数は非同期ジェネレータ
    for i in range(10):
        print(f"good_yield({i})")
        yield i


async def main():
    ret_value = await simple()
    print(f"await value {ret_value}")


asyncio.run(main())
```

非同期ジェネレータはawaitしてもダメです。
ジェネレータ(generator)は、for文で呼び出すのが普通です。

```
for value in ＜ジェネレータ＞:
   valueを使う。
```

世界的に有名なジェネレータは　range()　でしょうか。 

# TypeError: object generator can't be used in 'await' expression

先のものと似ていますが、 simple()は async_generator ではなく、普通の generator です。

### エラー例
```python
import asyncio


def simple():  # これは普通のジェネレータ
    for i in range(10):
        print(f"good_yield({i})")
        yield i


async def main():
    ret_value = await simple()
    print(f"await value {ret_value}")


asyncio.run(main())
```

# await value ```<generator object 関数 at アドレス>```がエターナル


### エターナル例
```python
import asyncio


def simple():  # yieldで戻る関数はジェネレータオブジェクト(Generator)
    for i in range(10):
        print(f"good_yield({i})")
        yield i

        
async def main():
    while True:
        ret_value = simple() # これはジェネレータを生成しているだけ
        print(f"await value {ret_value}")


asyncio.run(main())
```

ちなみにジェネレータは先に書いた通り、for文で使います。

```python
for value in sample():
   print(value)
```

# await value ```<async_generator object 関数名 at アドレス>```がエターナル

先の例のgeneratorがasync_generatorになっただけです。

### エターナル例
```python
import asyncio


async def simple(): # さっきの例にasyncを入れただけ。async_generatorに変わった
    for i in range(10):
        print(f"good_yield({i})")
        yield i


async def main():
    while True:
        ret_value = simple()
        print(f"await value {ret_value}")


asyncio.run(main())
```

非同期ジェネレータはasync forで使います。

```python
async for value in sample():
  print(value)
```

# TypeError: 'async_generator' object is not iterable

非同期ジェネレータオブジェクトがiterableではない。。。ジェネレータがiterableではないというメッセージはちょっと理不尽な気もしますね。

### エラー例
```python
import asyncio


async def simple(): # ★ここをasyncにした。
    for i in range(10):
        print(f"good_yield({i})")
        yield i


async def main():
    for ret_value in simple(): # async forにしないと理不尽なことを言われる。
        print(f"await value {ret_value}")


asyncio.run(main())
```

### 理不尽でない例
```python
import asyncio


async def simple(): 
    for i in range(10):
        print(f"good_yield({i})")
        yield i


async def main():
    async for ret_value in simple(): # ここにasyncを入れる
        print(f"await value {ret_value}")


asyncio.run(main())
```

# TypeError: 'async for' requires an object with ```__aiter__``` method, got generator

今度は async for で普通のジェネレータを呼んでしまった場合。　普通ジェネレータには```__iter__```が、非同期ジェネレータには```__aiter__```メソッドが付きます。

### エラー例
```python
import asyncio


def simple():  # ここのasyncを外すと __iter__ はあるけど __aiter__ がない。
    for i in range(10):
        print(f"good_yield({i})")
        yield i


async def main():
    async for ret_value in simple(): # ここにasyncがあるため要 __aiter__
        print(f"await value {ret_value}")


asyncio.run(main())
```

# RuntimeWarning: coroutine 'sleep' was never awaited

asyncio.sleep()に awaitを忘れた場合(sleepしてくれない）。

### ワーニング例
```python
import asyncio


async def whild_simple():
    i = 0
    while True:
        i += 1
        print(f"while simple {i}")
        asyncio.sleep(1)  # ここにawaitが抜けている
        yield i


async def main():

    async for ret_value in whild_simple():
        print(f"main ret_value = {ret_value}")


asyncio.run(main())
```

# RuntimeError: Task got bad yield: 0

ジェネレータをtaskで実行しちゃった場合

### エラー例
```python
import asyncio
import time


def whild_simple():  # 普通のジェネレータ
    i = 0
    while True:
        time.sleep(1)
        i += 1
        if i % 2 == 0:
            print(f"while yield {i}")
            yield i
        else:
            print(f"while not yield {i}")


async def main():

    task = asyncio.create_task(whild_simple()) # taskとして実行
    await task


asyncio.run(main())
```


### 動く例
```python
import asyncio
import time


async def while_simple():
    i = 0
    while True:
        time.sleep(1)
        i += 1
        if i % 2 == 0:
            print(f"while yield {i}")
            yield i
        else:
            print(f"while not yield {i}")


async def main():

    async for value in while_simple(): # ジェネレータは async for で呼ぶ
        print(value)


asyncio.run(main())
```

# TypeError: a coroutine was expected, got ```<async_generator object 関数 at アドレス>```

非同期ジェネレータをtaskとして実行しちゃった場合

### エラー例
```python
import asyncio
import time


async def while_simple(): # 非同期ジェネレータ
    i = 0
    while True:
        time.sleep(1)
        i += 1
        if i % 2 == 0:
            print(f"while yield {i}")
            yield i
        else:
            print(f"while not yield {i}")


async def main():

    task = asyncio.create_task(while_simple()) # 非同期ジェネレータをtaskで実行
    await task


asyncio.run(main())
```


以上。お疲れ様でした。