python死磕八之迭代器与生成器

  迭代是Python最强大的功能之一。初看起来,你可能会简单的认为迭代只不过是处理序列中元素的一种方法。 然而,绝非仅仅就是如此,还有很多你可能不知道的, 比如创建你自己的迭代器对象,在itertools模块中使用有用的迭代模式,构造生成器函数等等。

  一、for循环的内部原理?

  for循环迭代遍历对象首先是给对象添加了一个__iter__方法,使之每次可以调用next去访问下一个元素,直至遍历完遇到了StopIteration异常:

>>> items = [1, 2, 3]
>>> # Get the iterator
>>> it = iter(items) # Invokes items.__iter__()
>>> # Run the iterator
>>> next(it) # Invokes it.__next__()
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
Traceback (most recent call last):File "<stdin>", line 1, in <module>
StopIteration
>>>

 

  二、你想反方向迭代一个序列

  之前思路:调用reverse方法,再for循环遍历

  遗漏点:当我们需要处理的对象有__reverse__方法才行,比如我们给定一个Countdown类,想让他实现reverse方法:

class Countdown():def __init__(self,start):self.start = startdef __iter__(self):n = self.startwhile n > 0:yield nn -= 1def __reversed__(self):n = 0while n <= self.start:yield nn += 1

  当定义了__reversed__方法后,我们可以调用reverse方法了:

for i in Countdown(30):print(i)for i in reversed(Countdown(30)):print(i)

 

  三、你想得到一个由迭代器生成的切片对象,但是标准切片操作并不能做到。

  函数 itertools.islice() 正好适用于在迭代器和生成器上做切片操作。比如:

>>> def count(n):
...     while True:
...         yield n
...         n += 1
...
>>> c = count(0)
>>> c[10:20]
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'generator' object is not subscriptable>>> # Now using islice()
>>> import itertools
>>> for x in itertools.islice(c, 10, 20):
...     print(x)

  这里要着重强调的一点是 islice() 会消耗掉传入的迭代器中的数据。 必须考虑到迭代器是不可逆的这个事实。 所以如果你需要之后再次访问这个迭代器的话,那你就得先将它里面的数据放入一个列表中。

 

  四、跳过可迭代对象的开始部分

  你想遍历一个可迭代对象,但是它开始的某些元素你并不感兴趣,想跳过它们。

  首先介绍的是 itertools.dropwhile() 函数。使用时,你给它传递一个函数对象和一个可迭代对象。 它会返回一个迭代器对象,丢弃原有序列中直到函数返回Flase之前的所有元素,然后返回后面所有元素。

  假定你在读取一个开始部分是几行注释的源文件。比如:

  

>>> with open('/etc/passwd') as f:
... for line in f:
...     print(line, end='')
...
##
# User Database
#
# Note that this file is consulted directly only when the system is running
# in single-user mode. At other times, this information is provided by
# Open Directory.
...
##
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
...
>>>

  如果你想跳过开始部分的注释行的话,可以这样做:

>>> from itertools import dropwhile
>>> with open('/etc/passwd') as f:
...     for line in dropwhile(lambda line: line.startswith('#'), f):
...         print(line, end='')

  这个例子是基于根据某个测试函数跳过开始的元素。 如果你已经明确知道了要跳过的元素的个数的话,那么可以使用 itertools.islice() 来代替。比如:

>>> from itertools import islice
>>> items = ['a', 'b', 'c', 1, 4, 10, 15]
>>> for x in islice(items, 3, None):
...     print(x)
...
1
4
10
15
>>>

  最后需要着重强调的一点是,以上方案适用于所有可迭代对象,包括那些事先不能确定大小的, 比如生成器,文件及其类似的对象。

 

  五、你想迭代遍历一个集合中元素的所有可能的排列或组合

  1. itertools模块提供了三个函数来解决这类问题。 其中一个是 itertools.permutations() , 它接受一个集合并产生一个元组序列,每个元组由集合中所有元素的一个可能排列组成。 也就是说通过打乱集合中元素排列顺序生成一个元组,比如:

>>> items = ['a', 'b', 'c']
>>> from itertools import permutations
>>> for p in permutations(items):
...     print(p)
...
('a', 'b', 'c')
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')
>>>

如果你想得到指定长度的所有排列,你可以传递一个可选的长度参数。就像这样:

>>> for p in permutations(items, 2):
...     print(p)
...
('a', 'b')
('a', 'c')
('b', 'a')
('b', 'c')
('c', 'a')
('c', 'b')
>>>

 

  2.使用 itertools.combinations() 可得到输入集合中元素的所有的组合。比如:

>>> from itertools import combinations
>>> for c in combinations(items, 3):
...     print(c)
...
('a', 'b', 'c')>>> for c in combinations(items, 2):
...     print(c)
...
('a', 'b')
('a', 'c')
('b', 'c')>>> for c in combinations(items, 1):
...     print(c)
...
('a',)
('b',)
('c',)
>>>

  3.而函数 itertools.combinations_with_replacement() 允许同一个元素被选择多次,比如:

>>> for c in combinations_with_replacement(items, 3):
...     print(c)
...
('a', 'a', 'a')
('a', 'a', 'b')
('a', 'a', 'c')
('a', 'b', 'b')
('a', 'b', 'c')
('a', 'c', 'c')
('b', 'b', 'b')
('b', 'b', 'c')
('b', 'c', 'c')
('c', 'c', 'c')
>>>

 

以上几种是不是非常像我们数学课上所学的排列组合,注意,他们返回的都是可迭代对象。 
 六、zip,chain函数应用
比如,假设你头列表和一个值列表,就像下面这样:
headers = ['name', 'shares', 'price']
values = ['ACME', 100, 490.1]

  使用zip()可以让你将它们打包并生成一个字典:

s = dict(zip(headers,values))

 

  你想在多个对象执行相同的操作,但是这些对象在不同的容器中,你希望代码在不失可读性的情况下避免写重复的循环。

 itertools.chain() 方法可以用来简化这个任务。 它接受一个可迭代对象列表作为输入,并返回一个迭代器,有效的屏蔽掉在多个容器中迭代细节。 为了演示清楚,考虑下面这个例子:

  

>>> from itertools import chain
>>> a = [1, 2, 3, 4]
>>> b = ['x', 'y', 'z']
>>> for x in chain(a, b):
... print(x)
...
1
2
3
4
x
y
z

  itertools.chain() 接受一个或多个可迭代对象作为输入参数。 然后创建一个迭代器,依次连续的返回每个可迭代对象中的元素。 这种方式要比先将序列合并再迭代要高效的多。

  

  七、你想将一个多层嵌套的序列展开成一个单层列表

  可以写一个包含 yield from 语句的递归生成器来轻松解决这个问题。比如:

from collections import Iterabledef flatten(items, ignore_types=(str, bytes)):for x in items:if isinstance(x, Iterable) and not isinstance(x, ignore_types):yield from flatten(x)else:yield xitems = [1, 2, [3, 4, [5, 6], 7], 8]
# Produces 1 2 3 4 5 6 7 8
for x in flatten(items):print(x)

  语句 yield from 在你想在生成器中调用其他生成器作为子例程的时候非常有用。 如果你不使用它的话,那么就必须写额外的 for 循环了。比如:

def flatten(items, ignore_types=(str, bytes)):for x in items:if isinstance(x, Iterable) and not isinstance(x, ignore_types):for i in flatten(x):yield ielse:yield x

 

  注意:yield from 与 yield区别

yield from 后面需要加的是可迭代对象,它可以是普通的可迭代对象,也可以是迭代器,甚至是生成器。

使用yield

# 字符串
astr='ABC'
# 列表
alist=[1,2,3]
# 字典
adict={"name":"wangbm","age":18}
# 生成器
agen=(i for i in range(4,8))def gen(*args, **kw):for item in args:for i in item:yield inew_list=gen(astr, alist, adict, agen)
print(list(new_list))
# ['A', 'B', 'C', 1, 2, 3, 'name', 'age', 4, 5, 6, 7]

  使用yield from

# 字符串
astr='ABC'
# 列表
alist=[1,2,3]
# 字典
adict={"name":"wangbm","age":18}
# 生成器
agen=(i for i in range(4,8))def gen(*args, **kw):for item in args:yield from itemnew_list=gen(astr, alist, adict, agen)
print(list(new_list))
# ['A', 'B', 'C', 1, 2, 3, 'name', 'age', 4, 5, 6, 7]

  可以看出,yield from后面加上可迭代对象,他可以把可迭代对象里的每个元素一个一个的yield出来,对比yield来说代码更加简洁,结构更加清晰。

 

转载于:https://www.cnblogs.com/jimmyhe/p/10825082.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/424876.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第五十四期:Libra盟友纷纷“跳船”,联盟链还有戏吗?

曾经被诺贝尔奖得主斯蒂格利茨评价为“傻子才信”的Facebook数字加密货币项目Libra&#xff0c;自从出世开始就负面不断。最近在其首届理事会议前夕&#xff0c;PayPal、Visa、万事达、Stripe和eBay等全球型金融巨头“盟友”的相继退出&#xff0c;更使其遭遇了不少“看空”。 …

机器学习的一些注意事项

Single number evaluation metric 建一个评估指标。可以是准确率、召回率、F1 score。 Satisficing and Optimizing metric 很多时候我们需要协调多个因素&#xff0c;达到自己的目的。例如猫分类器&#xff0c;我们想要准确率&#xff0c;又想要运行时间快。这个时候我们可…

python time模块

时间戳、结构化时间、字符串时间 import time#时间戳 &#xff0c;大多时候用于计算 #从1970年0点0分0秒开始计算的秒数 print(time.time())#结构化时间------当地时间&#xff08;东8区&#xff09; #返回一个时间对象 print(time.localtime())#time.localtime()中默认参数为…

第五十五期:区块链将在2020年实现的重大改变

科技界的每家公司都已经拥有区块链战略。如果他们现在没有&#xff0c;他们就有可能错过了这个时代的一个机会。在过去几年中&#xff0c;许多企业已经对整体采用区块链技术的好处和相关风险进行了估算&#xff0c;分析和讨论。 科技界的每家公司都已经拥有区块链战略。如果他们…

[小技巧][JAVA][转换]整型int与字符char相互转换

借助String.valueOf()过渡 char -> String ->int char c; String str String.valueOf(c); int i Integer.parseInt(str); //int i Integer.valueOf(String).intValue(); //int i Integer.valueOf(String);[小技巧][JAVA][转换]整型int与字符串String相互转换 [小技巧…

为什么机器学习算法要与人类水平比较

原因 1 近年来机器学习的效果越来越好&#xff0c;能够和人类的相应能力做比较。 2 设计和构建机器学习系统&#xff0c;这个工作流程很高效。 因为种种原因&#xff0c;ML或者人都不可能超过Bayes Optimal Error 贝叶斯最优误差&#xff0c;ML随着时间推移会越来越接近贝…

npm run build后如何打开index.html跑起项目

Tip: built files are meant to be served over an HTTP server. Opening index.html over file:// wont work. 提示&#xff1a;构建的文件应该通过HTTP服务器提供服务。在文件&#xff1a;/上打开index.html不起作用。 其实直接本地就可以打开。。。 只需要在build配置文件…

第二十九期:运维之三大监控对比

Zabbix核心组件主要是Agent和Server&#xff0c;其中Agent主要负责采集数据并通过主动或者被动的方式采集数据发送到Server/Proxy&#xff0c;除此之外&#xff0c;为了扩展监控项&#xff0c;Agent还支持执行自定义脚本。 作者&#xff1a;艺术生的运维路来源&#xff1a;今日…

[Leetcode][第459题][JAVA][重复的字符串][子串][匹配]

【问题描述】[中等] 【解答思路】 1. 枚举 找出能整除的子串长度&#xff0c;再用substring遍历匹配即可 时间复杂度&#xff1a;O(N^2) 空间复杂度&#xff1a;O(1) class Solution {public boolean repeatedSubstringPattern(String s) {int len s.length();for(int i 1…

机器学习与人类比较

近些年&#xff0c;一些机器学习算法的效果&#xff0c;总是会提到与人类相应能力比较高出多少多少。为什么会这样&#xff1f; 1 人类在某些领域确实很擅长。例如图片分类。 2 近些年ML有了很大进步&#xff0c;效果非常好。 3 某些用途的ML与人类的能力比较&#xff0c;当…

第五十六期:百度CTO王海峰CNCC2019演讲:深度学习平台支撑产业智能化

百度CTO王海峰在会上发表题为《深度学习平台支撑产业智能化》的演讲&#xff0c;分享了百度关于深度学习技术推动人工智能发展及产业化应用的思考&#xff0c;并深度解读百度飞桨深度学习平台的优势&#xff0c;以及与百度智能云结合助力产业智能化的成果。 作者&#xff1a;佚…

【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)

版权声明&#xff1a;本文为博主原创文章&#xff0c;允许转载&#xff0c;但希望标注转载来源。 https://blog.csdn.net/qq_38410730/article/details/80312357IIC的基本介绍 IIC的简介 IIC&#xff08;Inter&#xff0d;Integrated Circuit&#xff09;总线是一种由PHILIPS公…

【数据结构与算法】广度优先遍历(BFS) 深度优先遍历(DFS)

一、 搜索算法 深度优先搜索和广度优先搜索是最暴力的图的搜索算法。算法的目标是&#xff0c;给定一张图&#xff0c;一对初始和终止节点&#xff0c;找到两节点之间的节点路径。&#xff08;代码均是找到两个节点之间的路径&#xff09; 广度优先搜索是一层一层搜索&#xf…

stack专题

20 Valid Parentheses 问题&#xff1a;没有意识到字符串中只包含字符&#xff1a;’(‘, ‘)’, ‘{‘, ‘}’, ‘[’ and ‘]’ 代码&#xff1a;git代码 682 Baseball Game 问题&#xff1a;错误在操作&#xff1a;top1 先弹出&#xff0c;top2 再弹出&#xff0c;还原到…

第三十期:简单好用的9个电脑必备工具!让你轻松10倍

下面 9 款工具都是精心挑选的电脑必备神器&#xff0c;涵盖你需要的各个方面&#xff0c;无论是安全防护、文件查找、解压加密还是娱乐都在其中&#xff1b;最最最重要的是&#xff0c;它们不但各个功能强大&#xff0c;而且非常轻便&#xff0c;没有弹窗广告、没有捆绑安装、也…

【数据结构与算法】字符串匹配 BF算法 RK算法

单模式串匹配 BF 算法和 RK 算法 BM 算法和 KMP 算法多模式串匹配算法 Trie 树和 AC 自动机 一、BF 算法 1&#xff0c;BF算法是Brute Force的缩写&#xff0c;中文译作暴力匹配算法&#xff0c;也叫朴素匹配算法。 2&#xff0c;两个概念&#xff1a;主串和模式串 如在字符串…

第三十一期:大数据分析师学习入门,10个数据可视化技巧

在这篇文章&#xff0c;我想和大家分享 10 个基本的中级和高级的绘图工具。我发现在现实生活中&#xff0c;当涉及到绘图解释你的数据时&#xff0c;这些工具非常有用。 作者&#xff1a;加米谷大数据来源&#xff1a;今日头条 我必须对你说实话&#xff1a;当我学习数据科学时…

stack专题2

85 Maximal Rectangle 问题&#xff1a;找到矩形内连续的都是1&#xff0c;这个矩形的面积。首先考虑到的是暴力搜索&#xff0c;不断枚举起始节点的x&#xff0c;y坐标&#xff0c;节点节点的x&#xff0c;y坐标。计算矩形面积的几个方法&#xff1a;1 一个一个元素遍历&…

[Leetcode][第491题][JAVA][递增子序列][回溯][RK算法]

【问题描述】[中等] 【解答思路】 1. 二进制枚举 哈希 复杂度 class Solution {List<Integer> temp new ArrayList<Integer>();List<List<Integer>> ans new ArrayList<List<Integer>>();Set<Integer> set new HashSet<In…

CentOS安装cheat和tldr

1.安装python和pip sudo yum -y install epel-release sudo yum install -y python python-pip python-setuptools sudo pip install --upgrade pip 2.安装tldr sudo pip install cheat tldr #最近遇到安装tldr时提示setuptools too old的报错&#xff0c;解决方法如下 pip ins…