当前位置: 首页 > news >正文

Python中的魔法方法(magic methods 或 special methods)-3

目录

  • 通过描述符管理属性
  • 使用 Iterators 和 Iterables 支持迭代
    • Creating Iterators 创建迭代器
    • 构建可迭代对象

通过描述符管理属性

Python 描述符是允许您对给定自定义类的属性进行精细控制的类。您可以使用 Descriptors 在给定类的属性之上添加类似函数的行为。

描述符类至少需要 .__get__() 特殊方法。但是,完整描述符协议由以下方法组成:

方法描述
__get__(self, instance, type=None)Getter 方法,该方法允许您检索 managed 属性的当前值
__set__(self, instance, value)允许您为 managed 属性设置新值的 Setter 方法
__delete__(self, instance)Deleter 方法,该方法允许您从包含类中删除 managed 属性
__set_name__(self, owner, name)名称 setter 方法,用于定义托管属性的名称

为了说明 Descriptors 的用途,假设您有一个 shapes.py 模块。您已经定义了 Circle、Square 和 Rectangle 类。您已经意识到需要验证圆的半径、正方形的边等参数。您还注意到,验证逻辑对于所有这些参数都是通用的。

在这种情况下,您可以使用描述符来管理验证逻辑,其中包括检查提供的值是否为正数。以下是此 Descriptors 的可能实现:

class PositiveNumber:def __set_name__(self, owner, name):self._name = namedef __get__(self, instance, owner):return instance.__dict__[self._name]def __set__(self, instance, value):if not isinstance(value, int | float) or value <= 0:raise ValueError("positive number expected")instance.__dict__[self._name] = value

在此类中,首先定义 .__set_name__() 特殊方法。owner 参数表示包含类,而 name 参数表示属性名称。

然后,定义 .__get__() 方法。此方法采用一个实例和对包含类的引用。在此方法中,使用 .dict 特殊属性来访问实例的命名空间并检索 managed 属性的值。

最后,定义 .__set__() 方法,该方法采用包含类的实例和 managed 属性的新值。在此方法中,您将检查提供的值是否为正数,在这种情况下,您将引发 ValueError 异常。否则,您将再次使用 .__dict__ 命名空间将 input 值分配给 managed 属性。

现在,您可以使用此描述符来定义形状的参数:

import math# ...class Circle:radius = PositiveNumber()def __init__(self, radius):self.radius = radiusdef area(self):return round(math.pi * self.radius**2, 2)class Square:side = PositiveNumber()def __init__(self, side):self.side = sidedef area(self):return round(self.side**2, 2)class Rectangle:height = PositiveNumber()width = PositiveNumber()def __init__(self, height, width):self.height = heightself.width = widthdef area(self):return self.height * self.width

在此代码中,突出显示的行显示了如何使用 PositiveNumber 描述符创建托管属性。请注意,托管属性必须是具有实例属性对应项的类属性。

以下是Shape使用方式:

>>> from shapes import Circle, Square, Rectangle>>> circle = Circle(-10)
Traceback (most recent call last):...
ValueError: positive number expected>>> square = Square(-20)
Traceback (most recent call last):...
ValueError: positive number expected>>> rectangle = Rectangle(-20, 30)
Traceback (most recent call last):...
ValueError: positive number expected

所有形状都会在实例化时验证输入参数。这是因为他们都使用你的 PositiveNumber 来管理他们的参数。这样,你就可以在所有类中重复使用验证代码。

使用 Iterators 和 Iterables 支持迭代

在 Python 中,迭代器和可迭代对象是两种不同但相关的工具,当您需要迭代数据流或容器时,它们可以派上用场。Iterators 支持并控制迭代过程,而 iterables 通常保存您可以迭代的数据。

迭代器和可迭代对象是 Python 编程中的基本组件。您将在几乎所有程序中直接或间接使用它们。在以下部分中,您将学习如何使用特殊方法将自定义类转换为迭代器和可迭代对象的基础知识。

Creating Iterators 创建迭代器

要在 Python 中创建迭代器,您需要两个特殊方法。通过实现这些方法,您将控制迭代过程。您可以定义在 for 循环或其他迭代构造中使用类时 Python 如何检索项。
下表显示了组成迭代器的方法。它们被称为迭代器协议:

方法描述
__iter__() 调用以初始化迭代器。它必须返回一个 iterator 对象。
__next__()调用以迭代迭代器。它必须返回数据流中的下一个值。

这两种方法都有自己的责任。在 .__iter__() 中,您通常返回当前对象 self。在 .__next__() 中,您需要返回序列中数据流中的下一个值。当数据流耗尽时,此方法必须引发 StopIteration。这样,Python 就知道迭代已经结束。
通过在自定义类中实现这两个方法,可以将它们转换为迭代器。例如,假设您要创建一个类,该类为斐波那契数列中的数字提供迭代器。在这种情况下,您可以编写以下解决方案:

class FibonacciIterator:def __init__(self, stop=10):self._stop = stopself._index = 0self._current = 0self._next = 1def __iter__(self):return selfdef __next__(self):if self._index < self._stop:self._index += 1fib_number = self._currentself._current, self._next = (self._next,self._current + self._next,)return fib_numberelse:raise StopIteration

在这个 FibonacciIterator 类中,您首先初始化一些 attributes。._stop 属性定义类将返回的值的数量。默认为 10。._index 属性保存序列中当前斐波那契值的索引。._current 和 ._next 属性分别表示斐波那契数列中的当前值和下一个值。

.__iter__() 中,你只需返回当前对象 self。在 Python 中创建迭代器时,这种做法很常见。

.__next__() 方法要复杂一些。在此方法中,您有一个条件,用于检查当前序列索引是否未达到 ._stop 值,在这种情况下,您可以递增当前索引以控制迭代过程。然后,您计算与当前索引对应的斐波那契数,并将结果返回给 .__next__() 的调用方。

当 ._index 增长到 ._stop 的值时,将引发 StopIteration 异常,这将终止迭代过程。

您的类现在已准备好进行迭代。以下是它的使用:

>>> from fib_iter import FibonacciIterator>>> for fib_number in FibonacciIterator():
...     print(fib_number)
...
0
1
1
2
3
5
8
13
21
34

FibonacciIterator 类实时计算新值,当您在循环中使用该类时,会按需生成值。当斐波那契值的数量增长到 10 时,该类将引发 StopIteration 异常,并且 Python 会终止循环。

构建可迭代对象

Iterables 与 iterators 略有不同。通常,当集合或容器实现 .__iter__() 特殊方法时,它是可迭代的。

例如,Python 内置容器类型(如列表、元组、字典和集)是可迭代对象。它们提供您可以迭代的数据流。但是,它们不提供 .__next__() 方法,该方法驱动迭代过程。因此,要使用 for 循环迭代可迭代对象,Python 会隐式创建一个迭代器。

例如,返回到 Stack 类。使用以下代码更新类以使其可迭代:

class Stack:# ...def __iter__(self):return iter(self.items[::-1])

请注意,.__iter__() 的这个实现不会返回当前对象 self。相反,该方法使用内置的 iter() 函数在堆栈中的项目上返回一个迭代器。iter() 函数为输入可迭代对象提供默认的 .__next__() 方法,使其成为一个成熟的迭代器。

在迭代之前反转堆栈中的项列表,以与元素从堆栈中弹出的顺序保持一致。在 Python 交互式会话中运行以下代码以试用 Stack 的这项新功能:

>>> from stack import Stack>>> stack = Stack([1, 2, 3, 4])>>> for value in stack:
...     print(value)
...
4
3
2
1

在此代码段中,您首先创建一个包含四个数字的 Stack 新实例。然后,在实例上启动 for 循环。循环在每次迭代中打印当前值。这表明如果你重复调用 .pop() ,顺序元素将被弹出。您的 Stack 类现在支持迭代。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 如何在 PyTorch 中定义一个简单的卷积神经网络?
  • 主窗口的设计与开发(二)
  • LeetCode字母异位词分组
  • k8s介绍
  • UDP报文结构
  • PurchaseorderController
  • JDBC的介绍续
  • [数据集][目标检测]电动车头盔佩戴检测数据集VOC+YOLO格式4235张5类别
  • 《深入浅出WPF》读书笔记.11Template机制(上)
  • 如何编写Linux PCI设备驱动器 之一
  • 推荐9个不同风格的音频频谱波形 听音乐怎么能少了它
  • FPGA基础知识
  • 分库分表:应对大数据量挑战的数据库扩展策略
  • Apache Ignite 在处理大规模数据时有哪些优势和局限性?
  • 【第0006页 · 数组】寻找重复数
  • 03Go 类型总结
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • javascript从右向左截取指定位数字符的3种方法
  • spring boot 整合mybatis 无法输出sql的问题
  • SpringBoot几种定时任务的实现方式
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • underscore源码剖析之整体架构
  • 解决iview多表头动态更改列元素发生的错误
  • 面试遇到的一些题
  • 前端知识点整理(待续)
  • 前端自动化解决方案
  • 通过几道题目学习二叉搜索树
  • 2017年360最后一道编程题
  • 第二十章:异步和文件I/O.(二十三)
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • ​Redis 实现计数器和限速器的
  • ​埃文科技受邀出席2024 “数据要素×”生态大会​
  • ​补​充​经​纬​恒​润​一​面​
  • ‌分布式计算技术与复杂算法优化:‌现代数据处理的基石
  • #LLM入门|Prompt#3.3_存储_Memory
  • (1)Nginx简介和安装教程
  • (AngularJS)Angular 控制器之间通信初探
  • (C++哈希表01)
  • (Java)【深基9.例1】选举学生会
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (待修改)PyG安装步骤
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (贪心) LeetCode 45. 跳跃游戏 II
  • (推荐)叮当——中文语音对话机器人
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (转)EXC_BREAKPOINT僵尸错误
  • (转)Scala的“=”符号简介
  • .Net CoreRabbitMQ消息存储可靠机制
  • .NET Micro Framework初体验
  • .net refrector
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...