Ric*_*ler 7 python python-typing
作为一个玩具示例,让我们使用斐波那契数列:
def fib(n: int) -> int:
if n < 2:
return 1
return fib(n - 2) + fib(n - 1)
Run Code Online (Sandbox Code Playgroud)
当然,如果我们尝试执行以下操作,计算机将会挂起:
print(fib(100))
Run Code Online (Sandbox Code Playgroud)
所以我们决定添加记忆功能。为了保持逻辑fib清晰,我们决定不改变fib,而是通过装饰器添加记忆:
from typing import Callable
from functools import wraps
def remember(f: Callable[[int], int]) -> Callable[[int], int]:
@wraps(f)
def wrapper(n: int) -> int:
if n not in wrapper.memory:
wrapper.memory[n] = f(n)
return wrapper.memory[n]
wrapper.memory = dict[int, int]()
return wrapper
@remember
def fib(n: int) -> int:
if n < 2:
return 1
return fib(n - 2) + fib(n - 1)
Run Code Online (Sandbox Code Playgroud)
现在如果我们:
print(fib(100))
Run Code Online (Sandbox Code Playgroud)
573147844013817084101
Run Code Online (Sandbox Code Playgroud)
然而,mypy抱怨"Callable[[int], int]" has no attribute "memory",这是有道理的,如果我尝试访问不属于声明类型的属性,通常我会想要这个抱怨......
那么,我们应该如何使用typing来表示wrapper,而 aCallable也具有属性 呢memory?
要将某些内容描述为“具有内存属性的可调用对象”,您可以定义一个协议(Python 3.8+,或带有 的早期版本typing_extensions):
from typing import Protocol
class Wrapper(Protocol):
memory: dict[int, int]
def __call__(self, n: int) -> int: ...
Run Code Online (Sandbox Code Playgroud)
在使用中,类型检查器知道 a 作为Wrappera 是有效的,并Callable[[int], int]允许对 进行赋值:return wrapperwrapper.memory
from functools import wraps
from typing import Callable, cast
def remember(f: Callable[[int], int]) -> Callable[[int], int]:
@wraps(f)
def _wrapper(n: int) -> int:
if n not in wrapper.memory:
wrapper.memory[n] = f(n)
return wrapper.memory[n]
wrapper = cast(Wrapper, _wrapper)
wrapper.memory = dict()
return wrapper
Run Code Online (Sandbox Code Playgroud)
不幸的是,这需要wrapper = cast(Wrapper, _wrapper),这不是类型安全的 -wrapper = cast(Wrapper, "foo")也可以很好地检查。
| 归档时间: |
|
| 查看次数: |
744 次 |
| 最近记录: |