1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# run-async
# A decorated `async def` is awaited like any other coroutine — both when the
# decorator returns the function untouched and when it wraps it in another
# coroutine function.
def identity(fn):
return fn
def double(fn):
async def wrapper(n):
return await fn(n) * 2
return wrapper
# === An identity decorator leaves the coroutine function alone ===
@identity
async def plain(n):
return n + 1
assert (await plain(1)) == 2 # pyright: ignore
# === A decorator may replace it with another coroutine function ===
@double
async def doubled(n):
return n + 1
assert (await doubled(1)) == 4 # pyright: ignore
# === Stacked: `double` applies first, then `identity` passes the wrapper on ===
@identity
@double
async def stacked(n):
return n + 1
assert (await stacked(3)) == 8 # pyright: ignore
# === A decorator can capture an enclosing local and use it in the wrapper ===
def make_offset(step):
def deco(fn):
async def wrapper(n):
return await fn(n) + step
return wrapper
return deco
@make_offset(100)
async def offset(n):
return n
assert (await offset(5)) == 105 # pyright: ignore