为何python3通过Protocol实现接口,为何在类实现接口的时候不进行标识实现接口?

python3 在使用Protocol实现接口interface的时候:

image.png

我们可以看到实现接口Animal的类:Duck并没有类似其他的语言标识出实现接口。

class Duck:
    def feed(self)-> None:
        print("Duck eats")

请问:
1、这样写的好处是什么呢?是基于什么原理实现的呢?
2、如果在其他的python模块定义此接口,到时候还可以直接这样使用吗?

阅读 390
avatarAI BotBETA

回答

  1. 这样写的好处是什么?是基于什么原理实现的呢?

    好处是 Python 的设计哲学强调简洁性和明确性。在 Python 中,不需要显式地声明一个类实现了某个接口(Protocol),因为 Python 是动态类型语言,可以在运行时检查对象是否实现了特定的方法。这种设计减少了代码的冗余,使得代码更加简洁易读。

    原理上,Python 使用鸭子类型(Duck Typing)原则:如果它看起来像鸭子、走路像鸭子、叫声像鸭子,那么它就是鸭子。这意味着,只要一个对象提供了接口中定义的方法,它就被认为是实现了该接口,而无需显式声明。

    使用 typing.Protocol 主要是为了在静态类型检查工具(如 MyPy)中提供更强的类型检查。即使不显式声明实现接口,只要类的方法签名与协议中的方法签名匹配,MyPy 就能识别出这个类实现了该协议。

  2. 如果在其他的python模块定义此接口,到时候还可以直接这样使用吗?

    是的,你可以在其他的 Python 模块中定义接口(Protocol),并在其他模块中直接使用它,无需修改实现接口的类。只要确保在使用接口之前已经正确导入了该接口定义即可。Python 的模块系统允许跨模块引用类和函数,因此你可以在不同的模块中定义和实现接口。

    例如,如果接口 Animal 定义在模块 animal_protocol.py 中,你可以在其他模块中这样使用:

    # animal_protocol.py
    from typing import Protocol
    
    class Animal(Protocol):
        def feed(self) -> None:
            ...
    
    # duck.py
    from animal_protocol import Animal
    
    class Duck:
        def feed(self) -> None:
            print("Duck eats")
    
    # 在这里,MyPy 会识别出 Duck 实现了 Animal 协议,即使 Duck 类没有显式声明这一点。

这种模块化的设计使得代码更加易于维护和扩展。

1 个回答

—>文档

问题1

Protocol是Python 3.8引入的一个特性,它允许你定义接口而不需要显式地实现它们。Protocol类本身并不强制要求类必须声明实现某个接口,只要类实现了接口中定义的方法,它就被认为是符合接口的。

Duck类没有显式地声明它实现了Animal接口,但由于它实现了feed方法,Python认为它符合Animal接口的要求。这样写比较灵活,代码更简洁和易于维护。

问题2

举个例子
例如,你可以在一个模块中定义接口:

# interfaces.py
from typing import Protocol

class Animal(Protocol):
    def feed(self) -> None:
        pass

然后在另一个模块中实现和使用这个接口:

# animals.py
from interfaces import Animal

class Duck:
    def feed(self) -> None:
        print("Duck eats")

def feed(animal: Animal) -> None:
    animal.feed()

duck = Duck()
feed(duck)
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏