# Protocol(3.8)
Protocol类是3.8新出的特性,主要用于类型注释时提示对象需要实现哪些些方法,类似于Java的Interface。
# 概述
Protocol 对 python 的主要好处在于处理外部库时,我们无法直接修改类型。当需要创建多态函数(可能接受外部库类或我们自己的类之一)时,我们没有共同的祖先来注释它。指定 Protocol 可以避免此问题。它允许我们仅定义我们期望带注释的参数具有的行为。
如果我们需要使用Protocol做子类issubclass或实例isinstance的判断,则需要在Protocol类前加一个@runtime_checkable装饰器。
这种方式类似于iterable(
isinstance(MyIterable(), Iterable))的检查,隶属于python的运行时协议。
# 示例
# 运行
如下代码可以正常运行:
如果解除注释执行(dog).quack会报AttributeError。
import time
from typing import Protocol,runtime_checkable
@runtime_checkable
class DuckLike(Protocol):
def walk(self, to: str) -> None:
...
def quack(self) -> str:
...
class Chicken:
def walk(self, to):
time.sleep(5)
self.location = to
def quack(self):
return "tok"
# dont have method quack
class Dog:
def walk(self, to):
time.sleep(1)
self.location = to
def add_to_zoo(duck: DuckLike):
print(
f"Adding {duck.__class__.__name__} to the zoo. "
)
# duck.walk("zoo")
# duck.quack()
add_to_zoo(Chicken()) # Type checker allows this
add_to_zoo(Dog()) # Type checker donesnt allow this
print(isinstance(Chicken(), DuckLike)) # True
print(isinstance(Dog(), DuckLike)) # False
print(issubclass(Chicken, DuckLike)) # True
print(issubclass(Dog, DuckLike)) # False
# 代码检查
但是执行代码检查会报错:
(test) lei@leideMacBook-Pro test % python -m mypy test.py
test.py:38: error: Argument 1 to "add_to_zoo" has incompatible type "Dog"; expected "DuckLike" [arg-type]
test.py:38: note: "Dog" is missing following "DuckLike" protocol member:
test.py:38: note: quack
Found 1 error in 1 file (checked 1 source file)
# 子类检查
print(isinstance(Chicken(), DuckLike)) # True
print(isinstance(Dog(), DuckLike)) # False
print(issubclass(Chicken, DuckLike)) # True
print(issubclass(Dog, DuckLike)) # False