一文了解Python的迭代器的实现
本文对迭代器的解释参考自:https://www.programiz.com/python-programming/iterator
最后自己使用迭代器实现一个公平洗牌类。
博主认为,理论来自实践,假若只学习理论而不实践,都是无用功。
Iterators in Python
迭代器在Python中无处不在。它们可以通过for循环优雅的使用。但是它的实现却被隐藏起来。
从技术上讲,Python迭代器对象必须实现两个特殊的方法,分别是__iter__() 和 __next__(),这两个方法也叫做Python的魔术方法,类似于一种迭代器协议。
如果我们可以将Python对象转换成一个迭代器,那么我们可以称这个对象是可以迭代的。像Python中的内置数据结构 list(列表)、tuple(元组)、string(字符串)等都是可迭代的。
注意:这里可迭代与迭代器是不同的概念,下面会讲到。
遍历迭代器
我们可以通过next()方法不断从迭代器中获取下一个元素。当迭代器中元素遍历完毕后,再次调用next()方法,迭代器会抛出StopIteration异常。下面是例子。
# :创建一个列表。
>>> test_list = [5, 4, 3, 2, 1, 0]
# :使用iter()将列表转换成迭代器。
>>> test_iter = iter(test_list)
# :使用next方法我们可以得到迭代器中的元素。
>>> print(next(test_iter))
5
>>> print(next(test_iter))
4
>>> print(next(test_iter))
3
>>> print(next(test_iter))
2
# :我们可以调用迭代器的魔法方法__next__获取下一个元素。
>>> print(test_iter.__next__())
1
>>> next(test_iter)
0
# :当迭代器中元素遍历完毕,再调用next()时迭代器抛出错误。
>>> next(test_iter)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
注意,这里我们如果不进行iter()操作的话,列表是否还支持next()等操作?我们看下面实际操作。
>>> test_list = [5, 4, 3, 2, 1, 0]
>>> next(test_list)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator
没错,程序发生报错,并且报错原因就是list并不是一个迭代器。
我们前面也强调过可迭代与迭代器并不是同一个概念,我们可以说list是可迭代的,但并不能说它是迭代器。
读到这里大家可能会疑问,平常使用for循环便利list的时候也没有主动将其变成迭代器操作的,别急,我们接着看下面的。
用于迭代器的for循环
>>> test_list = [5, 4, 3, 2, 1, 0]
>>> for i in test_list:
... print(i)
...
5
4
3
2
1
0
上面这个使用for循环遍历列表的例子也屡见不鲜了。实际上,for循环可以遍历任何可迭代对象。下面我们来看看for循环的实现。
iter_obj = iter(iterable) while True:
try:
element = next(iter_obj)
except StopIteration:
break
因此,for 循环在内部通过iter()方法产生一个迭代器对象。接着使用next()方法依次获取迭代器内部元素,直到抛出异常为止。
构建自定义的迭代器
前面我们也提到过对象中的__iter__()和__next__()方法。通过更改这两个魔法方法我们可以很轻易实现一个自定义的迭代器。
__iter__()返回一个迭代器对象,当然我们也可以在当中根据需要进行一些初始化操作。
__next__()返回下一项,此方法在调用到结尾时必须抛出StopIteration()。
下面这个例子实现要返回2的幂次方的迭代器对象。
class PowTwo: def __init__(self, max=0):
self.max = max def __iter__(self):
# :返回一个迭代器,可以是自己。
self.n = 0
return self def __next__(self):
# :判断是否结束遍历。
if self.n <= self.max:
result = 2 ** self.n
self.n += 1
return result
else:
raise StopIteration numbers = PowTwo(3) # :获取迭代器。
i = iter(numbers) print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i))
# :输出
1
2
4
8
Traceback (most recent call last):
File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module>
print(next(i))
File "<string>", line 18, in __next__
raise StopIteration
StopIteration
当然我们也可以使用for循环。
>>> for i in PowTwo(5):
... print(i)
...
1
2
4
8
16
32
注意
最后注意的是,迭代器要有尽头,类似于递归,迭代器也要有迭代结束条件来防止迭代器会无限迭代。
Knuth洗牌示例
这里结合Knuth洗牌算法实现一个洗牌类。此算法为知名的公平洗牌算法。此算法详细链接。
import random COLORS = ['红桃', '黑桃', '方片', '梅花'] class Knuth:
"""Kunuth洗牌算法""" def __init__(self):
self._pokers = []
for color in COLORS:
for i in range(1, 14):
self._pokers.append((i, color)) self._pokers.append(('大王'))
self._pokers.append(('小王')) # :记录扑克牌索引。
self._index = 0
# :一套扑克最多有54张牌。
self._max_index = 54 def __iter__(self):
return self def __next__(self):
if self._index < self._max_index:
card = self._pokers[self._index]
self._index += 1
return card
else:
raise StopIteration def shuffle_cards(self):
"""洗牌"""
for i in range(53, 0, -1):
swap_index = random.randint(0, i)
self._pokers[i], self._pokers[swap_index] = self._pokers[swap_index], self._pokers[i] # :计数索引归零。
self._index = 0 a = Knuth()
a.shuffle_cards()
for i in a:
print(i)
运行结果。
(2, '梅花')
(13, '红桃')
(3, '黑桃')
(6, '方片')
(5, '红桃')
大王
(3, '红桃')
(8, '方片')
(4, '黑桃')
(9, '方片')
(1, '红桃')
(10, '红桃')
(6, '梅花')
(8, '梅花')
...
一文了解Python的迭代器的实现的更多相关文章
- python函数-迭代器&生成器
python函数-迭代器&生成器 一.迭代器 1 可迭代协议 迭代:就是类似for循环,将某个数据集内的数据可以“一个挨着一个取出来” 可迭代协议: ① 协议内容:内部实现__iter__方法 ...
- python基础——迭代器
python基础——迭代器 我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器 ...
- python基础—迭代器、生成器
python基础-迭代器.生成器 1 迭代器定义 迭代的意思是重复做一些事很多次,就像在循环中做的那样. 只要该对象可以实现__iter__方法,就可以进行迭代. 迭代对象调用__iter__方法会返 ...
- python之迭代器与生成器
python之迭代器与生成器 可迭代 假如现在有一个列表,有一个int类型的12345.我们循环输出. list=[1,2,3,4,5] for i in list: print(i) for i i ...
- Python:迭代器的简单理解
一.什么是迭代器 迭代,顾名思义就是重复做一些事很多次(就现在循环中做的那样).迭代器是实现了__next__()方法的对象(这个方法在调用时不需要任何参数),它是访问可迭代序列的一种方式,通常其从序 ...
- 第十六篇 Python之迭代器与生成器
一.迭代器 一. 递归和迭代 生活实例说明什么是递归和迭代 A想去腾达大厦,问B怎么走路,B 说我不知道,我给你问问C,C也不知道,C又去问D,D知道,把路告诉了C,C又告诉B,B最后告诉A, 这就是 ...
- python——iterator迭代器|iterator详解——20140918|
-----------------------------------------------------------------------------前言--------------------- ...
- 搞清楚 Python 的迭代器、可迭代对象、生成器
很多伙伴对 Python 的迭代器.可迭代对象.生成器这几个概念有点搞不清楚,我来说说我的理解,希望对需要的朋友有所帮助. 1 迭代器协议 迭代器协议是核心,搞懂了这个,上面的几个概念也就很好理解了. ...
- 第五篇、Python之迭代器与生成器
1.迭代和递归等概念 循环(loop):指的是在满足条件的情况下,重复执行同一段代码.比如,while语句,for循环. 迭代(iterate):指的是按照某种顺序逐个访问列表中的每一项.比如,for ...
随机推荐
- AcWing 250 磁力快(分块)
题目传送门 在一片广袤无垠的原野上,散落着N块磁石. 每个磁石的性质可以用一个五元组(x,y,m,p,r)描述,其中x,y表示其坐标,m是磁石的质量,p是磁力,r是吸引半径. 若磁石A与磁石B的距离不 ...
- FZU - 1901 Period II (kmp)
传送门:FZU - 1901 题意:给你个字符串,让你求有多少个p可以使S[i]==S[i+P] (0<=i<len-p-1). 题解:这个题是真的坑,一开始怎么都觉得自己不可能错,然后看 ...
- hdu2546 饭卡
Problem Description 电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额.如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负) ...
- 用数组模拟STL中的srack(栈)和queue(队列)
我们在理解stack和queue的基础上可以用数组来代替这两个容器,因为STL中的stack和queue有可能会导致程序运行起来非常的慢,爆TLE,所以我们使用数组来模拟他们,不仅可以更快,还可以让代 ...
- LianLianKan HDU - 4272 状压dp
题意:长度为n(n<=1000)的栈,栈顶元素可以与下面1~5个数中相同的元素消去,问最后能都完全消去. 题解: 比如这个序列12345678910112这个位置的最远可匹配位置能到11为什么呢 ...
- [备忘] DevOps 工具上的准备清单(不断补充中……)
目录 概念 发展历程 工具清单 规划 概念 从字面上来看,"DevOps"一词是由英文 Development(开发)和 Operations (运维)组合而成,但它所代表的理念和 ...
- 如何实现批量上传----------Java解析excel
一.引子 在web平台开发中仅经常会遇到一下需要批量的问题,通常得做法是使用excel上传,下面主要介绍一下在实际开发中到的实例. 二.准备工作 1.需要导入的jar包(主要用到poi包) (1)po ...
- Leetcode(198)-打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定一个代表每 ...
- Storybook 最新教程
Storybook 最新教程 Storybook is the most popular UI component development tool for React, Vue, and Angul ...
- js sort map by key
js sort map by key Map map to array // Array.from() Object let obj = {}; for(let key of Object.keys( ...