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

Python 可迭代的对象、迭代器 和生成器(另一个示例:等差数列生成器)

另一个示例:等差数列生成器

典型的迭代器模式作用很简单——遍历数据结构。不过,即便不是从集
合中获取元素,而是获取序列中即时生成的下一个值时,也用得到这种
基于方法的标准接口。例如,内置的 range 函数用于生成有穷整数等
差数列(Arithmetic Progression,AP),itertools.count 函数用于生
成无穷等差数列。

下一节会说明 itertools.count 函数,本节探讨如何生成不同数字类
型的有穷等差数列。

下面我们在控制台中对稍后实现的 ArithmeticProgression 类做一些
测试,如示例 14-10 所示。这里,构造方法的签名是
ArithmeticProgression(begin, step[, end])。range() 函数与
这个 ArithmeticProgression 类的作用类似,不过签名是
range(start, stop[, step])。我选择使用不同的签名是因为,创
建等差数列时必须指定公差(step),而末项(end)是可选的。我还
把参数的名称由 start/stop 改成了 begin/end,以明确表明签名不
同。在示例 14-10 里的每个测试中,我都调用了 list() 函数,用于查
看生成的值。

示例 14-10 演示 ArithmeticProgression 类的用法

>>> ap = ArithmeticProgression(0, 1, 3)
>>> list(ap)
[0, 1, 2]
>>> ap = ArithmeticProgression(1, .5, 3)
>>> list(ap)
[1.0, 1.5, 2.0, 2.5]
>>> ap = ArithmeticProgression(0, 1/3, 1)
>>> list(ap)
[0.0, 0.3333333333333333, 0.6666666666666666]
>>> from fractions import Fraction
>>> ap = ArithmeticProgression(0, Fraction(1, 3), 1)
>>> list(ap)
[Fraction(0, 1), Fraction(1, 3), Fraction(2, 3)]
>>> from decimal import Decimal
>>> ap = ArithmeticProgression(0, Decimal('.1'), .3)
>>> list(ap)
[Decimal('0.0'), Decimal('0.1'), Decimal('0.2')]

注意,在得到的等差数列中,数字的类型与 begin 或 step 的类型一
致。如果需要,会根据 Python 算术运算的规则强制转换类型。在示例
14-10 中,有 int、float、Fraction 和 Decimal 数字组成的列表。
示例 14-11 列出的是 ArithmeticProgression 类的实现。
示例 14-11 ArithmeticProgression 类

class ArithmeticProgression:def __init__(self, begin, step, end=None): ➊self.begin = beginself.step = stepself.end = end # None -> 无穷数列def __iter__(self):result = type(self.begin + self.step)(self.begin) ➋forever = self.end is None ➌index = 0while forever or result < self.end:yield result ➎index += 1result = self.begin + self.step * index ➏

__init__ 方法需要两个参数:begin 和 step。end 是可选的,如
果值是 None,那么生成的是无穷数列。
❷ 这一行把 self.begin 赋值给 result,不过会先强制转换成前面的
加法算式得到的类型。
❸ 为了提高可读性,我们创建了 forever 变量,如果 self.end 属性的值是 None,那么 forever 的值是 True,因此生成的是无穷数列。
❹ 这个循环要么一直执行下去,要么当 result 大于或等于 self.end
时结束。如果循环退出了,那么这个函数也随之退出。
❺ 生成当前的 result 值。
❻ 计算可能存在的下一个结果。这个值可能永远不会产出,因为
while 循环可能会终止。

在示例 14-11 中的最后一行,我没有直接使用 self.step 不断地增加
result,而是选择使用 index 变量,把 self.begin 与 self.step 和
index 的乘积相加,计算 result 的各个值,以此降低处理浮点数时累
积效应致错的风险。

示例 14-11 中定义的 ArithmeticProgression 类能按预期那样使用。
这是个简单的示例,说明了如何使用生成器函数实现特殊的 __iter__
方法。然而,如果一个类只是为了构建生成器而去实现 __iter__
法,那还不如使用生成器函数。毕竟,生成器函数是制造生成器的工
厂。

示例 14-12 中定义了一个名为 aritprog_gen 的生成器函数,作用与
ArithmeticProgression 类一样,只不过代码量更少。如果把
ArithmeticProgression 类换成 aritprog_gen 函数,示例 14-10 中
的测试也都能通过。

示例 14-12 aritprog_gen 生成器函数

def aritprog_gen(begin, step, end=None):result = type(begin + step)(begin)forever = end is Noneindex = 0while forever or result < end:yield resultindex += 1result = begin + step * index

示例 14-12 很棒,不过始终要记住,标准库中有许多现成的生成器。下
一节会使用 itertools 模块实现,那个版本更棒。

使用itertools模块生成等差数列
Python 3.4 中的 itertools 模块提供了 19 个生成器函数,结合起来使
用能实现很多有趣的用法。

例如,itertools.count 函数返回的生成器能生成多个数。如果不传
入参数,itertools.count 函数会生成从零开始的整数数列。不过,
我们可以提供可选的 start 和 step 值,这样实现的作用与
aritprog_gen 函数十分相似:

>>> import itertools
>>> gen = itertools.count(1, .5)
>>> next(gen)
1 >>> next(gen)
1.5
>>> next(gen)
2.0
>>> next(gen)
2.5

然而,itertools.count 函数从不停止,因此,如果调用
list(count()),Python 会创建一个特别大的列表,超出可用内存,在
调用失败之前,电脑会疯狂地运转。

不过,itertools.takewhile 函数则不同,它会生成一个使用另一个
生成器的生成器,在指定的条件计算结果为 False 时停止。因此,可
以把这两个函数结合在一起使用,编写下述代码:

>>> gen = itertools.takewhile(lambda n: n < 3, itertools.count(1, .5))
>>> list(gen)
[1, 1.5, 2.0, 2.5]

示例 14-13 利用 takewhile 和 count 函数,写出的代码流畅而简短。
示例 14-13 aritprog_v3.py:与前面的 aritprog_gen 函数作用相

import itertools
def aritprog_gen(begin, step, end=None):
first = type(begin + step)(begin)
ap_gen = itertools.count(first, step)
if end is not None:
ap_gen = itertools.takewhile(lambda n: n < end, ap_gen)
return ap_gen

注意,示例 14-13 中的 aritprog_gen 不是生成器函数,因为定义体中
没有 yield 关键字。但是它会返回一个生成器,因此它与其他生成器
函数一样,也是生成器工厂函数。
示例 14-13 想表达的观点是,实现生成器时要知道标准库中有什么可
用,否则很可能会重新发明轮子。鉴于此,下一节会介绍一些现成的生
成器函数。


文章转载自:
http://aerosinusitis.tmizpp.cn
http://bonanza.tmizpp.cn
http://abortus.tmizpp.cn
http://bondholder.tmizpp.cn
http://bitartrate.tmizpp.cn
http://abounding.tmizpp.cn
http://allier.tmizpp.cn
http://amildar.tmizpp.cn
http://aquiculture.tmizpp.cn
http://audiotypist.tmizpp.cn
http://accidently.tmizpp.cn
http://chokey.tmizpp.cn
http://branching.tmizpp.cn
http://censor.tmizpp.cn
http://camas.tmizpp.cn
http://booze.tmizpp.cn
http://charcuterie.tmizpp.cn
http://attendant.tmizpp.cn
http://annatto.tmizpp.cn
http://chlorous.tmizpp.cn
http://cholane.tmizpp.cn
http://assault.tmizpp.cn
http://carpogonial.tmizpp.cn
http://breeziness.tmizpp.cn
http://bluppy.tmizpp.cn
http://bullshit.tmizpp.cn
http://antecedency.tmizpp.cn
http://benign.tmizpp.cn
http://boride.tmizpp.cn
http://associative.tmizpp.cn
http://www.dtcms.com/a/262197.html

相关文章:

  • 设计模式 | 组合模式
  • Excel之证件照换底色3
  • Ubuntu无法显示IP地址
  • 【算法设计与分析】(二)什么是递归,以及分治法的基本思想
  • Mac homebrew 安装教程
  • 左神算法之Zigzag方式打印矩阵
  • Redis分布式锁核心原理源码
  • SpringCloud系列(40)--SpringCloud Gateway的Filter的简介及使用
  • 和ai对话:讨论一个简单的理财方案
  • Halcon 常用算子总结
  • 基于 SpringBoot 实现一个 JAVA 代理 HTTP / WS
  • MyBatis实战指南(八)MyBatis日志
  • 热传导方程能量分析与边界条件研究
  • HarmonyOS实战:自定义表情键盘
  • < OS 有关 4 台 Ubuntu VPSs 正在被攻击:nginx 之三> 记录、分析、防护的过程 配置 ufw Fail2Ban 保护网络上的主机
  • 个人计算机系统安全、网络安全、数字加密与认证
  • Github 2025-06-29php开源项目日报 Top10
  • RK3588集群服务器性能优化案例:电网巡检集群、云手机集群、工业质检集群
  • Mac电脑手动安装原版Stable Diffusion,开启本地API调用生成图片
  • 基于云的平板挠度模拟:动画与建模-AI云计算数值分析和代码验证
  • Linux中部署Nacos保姆级教程
  • Wpf布局之WrapPanel面板!
  • Java面试宝典:基础二
  • JSON + 存储过程:SaaS 架构下的统一接口与租户定制之道
  • 2025年渗透测试面试题总结-2025年HW(护网面试) 19(题目+回答)
  • OpenCV读取照片和可视化详解和代码示例
  • Java 数据结构 泛型
  • Hive SQL 快速入门指南
  • 线性相关和线性无关
  • 【记录】服务器多用户共享Conda环境——Ubuntu24.04