鸭子类型遇到类型提示:在 Python 中使用协议

鸭子类型遇到类型提示:在 python 中使用协议

python 的动态特性和对鸭子类型的支持长期以来因其灵活性而受到称赞。然而,随着代码库变得越来越大、越来越复杂,静态类型检查的好处变得越来越明显。但是我们如何协调鸭子类型的灵活性和静态类型检查的安全性呢?进入python的protocol类。

在本教程中,您将学习:

什么是鸭子类型以及 python 中如何支持它鸭子打字的优点和缺点抽象基类(abc)如何尝试解决打字问题如何使用协议来获得两全其美的效果:通过静态类型检查实现鸭子类型灵活性

了解鸭子类型

鸭子类型是一种编程概念,其中对象的类型或类不如它定义的方法重要。它基于这样的想法:“如果它看起来像鸭子,像鸭子一样游泳,像鸭子一样嘎嘎叫,那么它可能就是一只鸭子。”

在 python 中,完全支持鸭子类型。例如:

class duck:    def quack(self):        print("quack!")class person:    def quack(self):        print("i'm imitating a duck!")def make_it_quack(thing):  # note: no type hint here    thing.quack()duck = duck()person = person()make_it_quack(duck)    # output: quack!make_it_quack(person)  # output: i'm imitating a duck!

在这个例子中,make_it_quack 不关心事物的类型。它只关心这个东西有一个江湖方法。请注意,thing 参数没有类型提示,这在鸭子类型代码中很常见,但可能会导致较大代码库中出现问题。

立即学习“Python免费学习笔记(深入)”;

鸭子打字的优点和缺点

鸭子打字有几个优点:

灵活性:它允许更灵活的代码,不依赖于特定类型。更轻松的代码重用:您可以在新上下文中使用现有的类而无需修改。强调行为:它关注对象可以做什么,而不是它是什么。

但是,它也有一些缺点:

缺乏清晰度:可能不清楚对象需要实现哪些方法。运行时错误:与类型相关的错误仅在运行时捕获。较少的 ide 支持:ide 很难提供准确的自动完成和错误检查。

abc 解决方案

解决这些问题的一种方法是使用抽象基类(abc)。这是一个例子:

from abc import abc, abstractmethodclass quacker(abc):    @abstractmethod    def quack(self):        passclass duck(quacker):    def quack(self):        print("quack!")class person(quacker):    def quack(self):        print("i'm imitating a duck!")def make_it_quack(thing: quacker):    thing.quack()duck = duck()person = person()make_it_quack(duck)make_it_quack(person)

虽然这种方法提供了更好的类型检查和更清晰的接口,但它也有缺点:

它需要继承,这可能会导致不灵活的层次结构。它不适用于您无法修改的现有类。这违背了python的“鸭子打字”哲学。

协议:两全其美

python 3.8引入了protocol类,它允许我们定义接口而不需要继承。以下是我们如何使用它:

from typing import protocolclass quacker(protocol):    def quack(self):...class duck:    def quack(self):        print("quack!")class person:    def quack(self):        print("i'm imitating a duck!")def make_it_quack(thing: quacker):    thing.quack()duck = duck()person = person()make_it_quack(duck)make_it_quack(person)

让我们来分解一下:

我们定义了一个quacker协议,指定了我们期望的接口。我们的 duck 和 person 类不需要继承任何东西。我们可以使用 make_it_quack 的类型提示来指定它需要 quacker。

这种方法给我们带来了几个好处:

静态类型检查:ide 和类型检查器可以在运行前捕获错误。不需要继承:现有的类只要有正确的方法就可以工作。清晰的接口:协议明确定义了期望的方法。

这是一个更复杂的示例,展示了协议如何根据需要(形状)变得复杂,同时保持域类(圆形、矩形)平坦:

from typing import Protocol, Listclass Drawable(Protocol):    def draw(self): ...class Resizable(Protocol):    def resize(self, factor: float): ...class Shape(Drawable, Resizable, Protocol):    passdef process_shapes(shapes: List[Shape]):    for shape in shapes:        shape.draw()        shape.resize(2.0)# Example usageclass Circle:    def draw(self):        print("Drawing a circle")    def resize(self, factor: float):        print(f"Resizing circle by factor {factor}")class Rectangle:    def draw(self):        print("Drawing a rectangle")    def resize(self, factor: float):        print(f"Resizing rectangle by factor {factor}")# This works with any class that has draw and resize methods,# regardless of its actual type or inheritanceshapes: List[Shape] = [Circle(), Rectangle()]process_shapes(shapes)

在此示例中,circle 和 rectangle 不继承自 shape 或任何其他类。他们只是实现所需的方法(绘制和调整大小)。得益于 shape 协议,process_shapes 函数可以与任何具有这些方法的对象一起使用。

概括

python 中的协议提供了一种将静态类型引入鸭子类型代码的强大方法。它们允许我们在类型系统中指定接口,而不需要继承,保持鸭子类型的灵活性,同时增加静态类型检查的好处,

通过使用协议,您可以:

为您的代码定义清晰的接口获得更好的 ide,(静态类型检查),支持并更早捕获错误保持鸭子打字的灵活性利用类型检查来检查您无法修改的类。

如果您想了解有关 python 中的协议和类型提示的更多信息,请查看有关类型模块的 python 官方文档,或探索 mypy 等高级静态类型检查工具。

快乐编码,愿你的鸭子总是因类型安全而嘎嘎叫!

您可以在这里找到更多我的内容,包括我的时事通讯

以上就是鸭子类型遇到类型提示:在 Python 中使用协议的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1348450.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月13日 12:02:59
下一篇 2025年12月13日 12:03:14

相关推荐

  • 性能追求第二部分:Perl 与 Python

    运行了一个玩具性能示例后,我们现在将稍微偏离主题并将性能与 进行对比一些 python 实现。首先让我们设置计算阶段,并提供命令行python 脚本的功能。 import argparseimport timeimport mathimport numpy as npimport osfrom nu…

    2025年12月13日
    000
  • python如何计算销售额

    通过使用 Python 编程语言,您可以自动化电子商务销售额计算,获取准确的数据。导入库:import pandas as pd加载销售数据到 DataFrame 中。计算总销售额:使用 df.sum() 方法计算 DataFrame 中所有销售值的总和。按产品类别计算销售额:使用 df.group…

    2025年12月13日
    000
  • python如何定义一个函数?

    Python 函数的定义方法有三种:使用 def 关键字和函数参数定义。使用匿名 lambda 表达式在一行中定义。使用 functools.partial 函数预绑定参数。 如何定义一个 Python 函数 在 Python 中定义函数有多种方法。最常见的方法是使用 def 关键字,后跟函数名称和…

    2025年12月13日
    000
  • python如何获取当前日期

    在 Python 中获取当前日期有两种方法:使用 datetime.date.today() 直接获取当前日期(不含时间部分);使用 datetime.datetime.now().date() 获取当前日期和时间,然后提取日期部分。 如何用 Python 获取当前日期 获取当前日期的两种方法: 1…

    2025年12月13日
    000
  • python如何建立新文件夹

    对于使用 Python 创建新文件夹,步骤如下:导入 os 模块。使用 os.makedirs() 函数传递文件夹路径。处理错误,使用 try 和 except 语句捕获 OSError 异常。检查文件夹是否存在,使用 os.path.exists() 函数避免 FileExistsError 异常…

    2025年12月13日
    000
  • python如何换行继续编写

    Python 换行有三种方法:1)使用反斜杠();2)使用括号(());3)使用分号(;)。单行代码用反斜杠最简便,多行代码用括号更清晰,分号不推荐用于换行。 如何使用 Python 换行继续编写 在编写 Python 代码时,有时需要暂时断开一行,并在下一行继续编写。这通常是为了增强代码的可读性或…

    2025年12月13日
    000
  • python如何换行写代码

    Python 中可使用以下三种方法换行写代码:1. 在行末使用反斜杠 ();2. 使用括号 ();3. 使用分号 (;)。三重引号 (“””或”’) 可定义多行字符串。 Python 中换行写代码 在 Python 中,使用反斜杠()字符可…

    2025年12月13日
    000
  • python如何换行输入代码

    Python中换行输入代码的方法有:使用’n’符号使用多行字符串使用re.compile()使用第三方库(如line-by-line) Python中换行输入代码的方法 在Python中,可以使用input()函数从用户获取输入。默认情况下,input()函数会将所有输入视为…

    2025年12月13日
    000
  • python如何下载pip库

    使用 Pip 库可通过 pip install 命令下载 Python 库。额外选项包括:升级包(–U)、安装特定版本(== 标识符)、从特定源安装(–index-url)、离线安装(-r 标识符)和验证安装(pip freeze)。 如何使用 Python 下载 Pip 库…

    2025年12月13日
    000
  • python如何编写函数

    函数是可重复使用的代码块,可执行特定任务,需要输入,执行处理,并返回输出。编写 Python 函数的步骤包括:1. 定义函数;2. 添加参数;3. 编写函数体;4. 返回值;5. 调用函数。 如何编写 Python 函数 什么是函数? 函数是一组可重复使用的代码块,用于执行特定的任务。它们可以接受输…

    2025年12月13日
    000
  • 写python如何另起一行

    在 Python 中可使用不同的方法另起一行,包括:使用换行符(适用于不同的操作系统)使用 print() 方法,指定 “n” 作为结尾使用 write() 方法,写入 “n”使用特殊字符序列 “x0a”,等价于换行符 如何用 …

    2025年12月13日
    000
  • if __name__ =&#__main__&# 在 Python 中做什么?

    你可能在 python 脚本中经常看到这行代码 if __name__==”__main__”: ,但不知道它的实际用途是什么。别担心,因为在这个简短的博客中我们将讨论这个 当您直接运行程序或脚本时,python 会自动将“main”分配给特殊的name变量。这样做基本上是为…

    2025年12月13日
    000
  • 高知 D Soft Technologies 的 Python 学生取得的令人瞩目的成就

    在高知的 D Soft Technologies,我们的 Python 课程一直是周围许多最优秀学生的起点。这些学生每天都在挑战 Python 所能完成的极限。他们在这里期间接触过各种项目,从开发网络应用程序到构建机器学习模型。这些学生所做的很多工作都解决了实际问题,不仅展示了他们在技术上学到的知识…

    2025年12月13日
    000
  • python需要插件才能运行吗

    否,Python 无需插件即可运行。它附带了一个标准库,提供了各种功能,而无需安装任何额外的插件。但是,在某些情况下您可能需要插件,例如:① 安装特定库或模块 ② 增强 IDE 集成 ③ 集成第三方软件。 Python 需要插件才能运行吗? 回答:否,Python 无需插件即可运行。 详细解答: P…

    2025年12月13日
    000
  • python如何新建一个文件夹

    Python 中创建文件夹的方法:导入 os 模块。指定文件夹路径。使用 os.makedirs() 函数创建文件夹。处理潜在的异常。验证文件夹是否已创建。 如何使用 Python 创建文件夹 在 Python 中,可以使用 os 模块来创建文件夹。以下步骤演示如何创建文件夹: 导入 os 模块 i…

    2025年12月13日
    000
  • python如何安装pip工具

    Pip 是 Python 包管理器,用于安装、管理和卸载 Python 包。安装 Pip 的步骤包括:检查现有 pip 版本。如果未安装,下载 get-pip.py 脚本并使用 Python 运行它。验证 pip 安装。 如何安装 Python 的 Pip 工具 Pip 是 Python 包管理器,…

    2025年12月13日
    000
  • 使用 Python3 构建 Web 应用程序

    要使用 python 3 构建 web 应用程序,您可以使用 flask 框架。 flask 轻量、灵活,非常适合快速创建 web 应用程序。以下是开始的步骤: 安装 flask: 首先,激活你的python环境并使用pip安装flask: source env/bin/activate # act…

    2025年12月13日
    000
  • 如何预处理数据集

    简介 泰坦尼克号数据集是数据科学和机器学习项目中使用的经典数据集。它包含有关泰坦尼克号乘客的信息,目标通常是预测哪些乘客在灾难中幸存。在构建任何预测模型之前,预处理数据以确保数据干净且适合分析至关重要。这篇博文将指导您完成使用 python 预处理泰坦尼克号数据集的基本步骤。 第 1 步:加载数据 …

    2025年12月13日
    000
  • eek Data 职业训练营:方向和基础

    5 周数据职业训练营 是 LuxDevHQ 计划,旨在揭开数据职业的神秘面纱,让广泛的人可以免费学习,无论他们的背景或专业知识如何。 这些计划提供了学习结构和参考空间,您可以在其中获得构建您的“世界级数据职业”所需的所有材料。 在该计划中,我们认识到数据职业有潜力为各个领域和行业带来有价值的见解和解…

    2025年12月13日
    000
  • Python:“replace()”和“resub()”方法之间的差异

    介绍 python 中的 .replace() 方法和 .re.sub() 函数都用于替换部分字符串,但它们具有不同的功能和用例。以下是它们之间的根本区别: 模块和使用上下文:.replace():属于str类。用作字符串对象的方法。语法:str.replace(old, new, count=-1…

    2025年12月13日
    000

发表回复

登录后才能评论
关注微信