本文对迭代器的解释参考自:https://www.programiz.com/python-programming/iterator

  最后自己使用迭代器实现一个公平洗牌类。

  博主认为,理论来自实践,假若只学习理论而不实践,都是无用功。

Iterators in Python

  迭代器在Python中无处不在。它们可以通过for循环优雅的使用。但是它的实现却被隐藏起来。

  从技术上讲,Python迭代器对象必须实现两个特殊的方法,分别是__iter__() 和 __next__(),这两个方法也叫做Python的魔术方法,类似于一种迭代器协议。

  如果我们可以将Python对象转换成一个迭代器,那么我们可以称这个对象是可以迭代的。像Python中的内置数据结构 list(列表)、tuple(元组)、string(字符串)等都是可迭代的。

  注意:这里可迭代与迭代器是不同的概念,下面会讲到。

遍历迭代器

  我们可以通过next()方法不断从迭代器中获取下一个元素。当迭代器中元素遍历完毕后,再次调用next()方法,迭代器会抛出StopIteration异常。下面是例子。

  1. # :创建一个列表。
  2. >>> test_list = [5, 4, 3, 2, 1, 0]
  3. # :使用iter()将列表转换成迭代器。
  4. >>> test_iter = iter(test_list)
  5. # :使用next方法我们可以得到迭代器中的元素。
  6. >>> print(next(test_iter))
  7. 5
  8. >>> print(next(test_iter))
  9. 4
  10. >>> print(next(test_iter))
  11. 3
  12. >>> print(next(test_iter))
  13. 2
  14. # :我们可以调用迭代器的魔法方法__next__获取下一个元素。
  15. >>> print(test_iter.__next__())
  16. 1
  17. >>> next(test_iter)
  18. 0
  19. # :当迭代器中元素遍历完毕,再调用next()时迭代器抛出错误。
  20. >>> next(test_iter)
  21. Traceback (most recent call last):
  22. File "<stdin>", line 1, in <module>
  23. StopIteration

  注意,这里我们如果不进行iter()操作的话,列表是否还支持next()等操作?我们看下面实际操作。

  1. >>> test_list = [5, 4, 3, 2, 1, 0]
  2. >>> next(test_list)
  3. Traceback (most recent call last):
  4. File "<stdin>", line 1, in <module>
  5. TypeError: 'list' object is not an iterator

  没错,程序发生报错,并且报错原因就是list并不是一个迭代器。

  我们前面也强调过可迭代与迭代器并不是同一个概念,我们可以说list是可迭代的,但并不能说它是迭代器。

  读到这里大家可能会疑问,平常使用for循环便利list的时候也没有主动将其变成迭代器操作的,别急,我们接着看下面的。

用于迭代器的for循环

  1. >>> test_list = [5, 4, 3, 2, 1, 0]
  2. >>> for i in test_list:
  3. ... print(i)
  4. ...
  5. 5
  6. 4
  7. 3
  8. 2
  9. 1
  10. 0

  上面这个使用for循环遍历列表的例子也屡见不鲜了。实际上,for循环可以遍历任何可迭代对象。下面我们来看看for循环的实现。

  1. iter_obj = iter(iterable)
  2.  
  3. while True:
  4. try:
  5. element = next(iter_obj)
  6. except StopIteration:
  7. break

  因此,for 循环在内部通过iter()方法产生一个迭代器对象。接着使用next()方法依次获取迭代器内部元素,直到抛出异常为止。

构建自定义的迭代器

  前面我们也提到过对象中的__iter__()和__next__()方法。通过更改这两个魔法方法我们可以很轻易实现一个自定义的迭代器。

  __iter__()返回一个迭代器对象,当然我们也可以在当中根据需要进行一些初始化操作。

  __next__()返回下一项,此方法在调用到结尾时必须抛出StopIteration()。

  下面这个例子实现要返回2的幂次方的迭代器对象。

  1. class PowTwo:
  2.  
  3. def __init__(self, max=0):
  4. self.max = max
  5.  
  6. def __iter__(self):
  7. # :返回一个迭代器,可以是自己。
  8. self.n = 0
  9. return self
  10.  
  11. def __next__(self):
  12. # :判断是否结束遍历。
  13. if self.n <= self.max:
  14. result = 2 ** self.n
  15. self.n += 1
  16. return result
  17. else:
  18. raise StopIteration
  19.  
  20. numbers = PowTwo(3)
  21.  
  22. # :获取迭代器。
  23. i = iter(numbers)
  24.  
  25. print(next(i))
  26. print(next(i))
  27. print(next(i))
  28. print(next(i))
  29. print(next(i))

    # :输出
  1. 1
  2. 2
  3. 4
  4. 8
  5. Traceback (most recent call last):
  6. File "/home/bsoyuj/Desktop/Untitled-1.py", line 32, in <module>
  7. print(next(i))
  8. File "<string>", line 18, in __next__
  9. raise StopIteration
  10. StopIteration

  当然我们也可以使用for循环。

  1. >>> for i in PowTwo(5):
  2. ... print(i)
  3. ...
  4. 1
  5. 2
  6. 4
  7. 8
  8. 16
  9. 32

注意

  最后注意的是,迭代器要有尽头,类似于递归,迭代器也要有迭代结束条件来防止迭代器会无限迭代。

Knuth洗牌示例

  这里结合Knuth洗牌算法实现一个洗牌类。此算法为知名的公平洗牌算法。此算法详细链接

  

  1. import random
  2.  
  3. COLORS = ['红桃', '黑桃', '方片', '梅花']
  4.  
  5. class Knuth:
  6. """Kunuth洗牌算法"""
  7.  
  8. def __init__(self):
  9. self._pokers = []
  10. for color in COLORS:
  11. for i in range(1, 14):
  12. self._pokers.append((i, color))
  13.  
  14. self._pokers.append(('大王'))
  15. self._pokers.append(('小王'))
  16.  
  17. # :记录扑克牌索引。
  18. self._index = 0
  19. # :一套扑克最多有54张牌。
  20. self._max_index = 54
  21.  
  22. def __iter__(self):
  23. return self
  24.  
  25. def __next__(self):
  26. if self._index < self._max_index:
  27. card = self._pokers[self._index]
  28. self._index += 1
  29. return card
  30. else:
  31. raise StopIteration
  32.  
  33. def shuffle_cards(self):
  34. """洗牌"""
  35. for i in range(53, 0, -1):
  36. swap_index = random.randint(0, i)
  37. self._pokers[i], self._pokers[swap_index] = self._pokers[swap_index], self._pokers[i]
  38.  
  39. # :计数索引归零。
  40. self._index = 0
  41.  
  42. a = Knuth()
  43. a.shuffle_cards()
  44. for i in a:
  45. print(i)

  运行结果。

  1. (2, '梅花')
  2. (13, '红桃')
  3. (3, '黑桃')
  4. (6, '方片')
  5. (5, '红桃')
  6. 大王
  7. (3, '红桃')
  8. (8, '方片')
  9. (4, '黑桃')
  10. (9, '方片')
  11. (1, '红桃')
  12. (10, '红桃')
  13. (6, '梅花')
  14. (8, '梅花')
  15. ...

  

一文了解Python的迭代器的实现的更多相关文章

  1. python函数-迭代器&生成器

    python函数-迭代器&生成器 一.迭代器 1 可迭代协议 迭代:就是类似for循环,将某个数据集内的数据可以“一个挨着一个取出来” 可迭代协议: ① 协议内容:内部实现__iter__方法 ...

  2. python基础——迭代器

    python基础——迭代器 我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器 ...

  3. python基础—迭代器、生成器

    python基础-迭代器.生成器 1 迭代器定义 迭代的意思是重复做一些事很多次,就像在循环中做的那样. 只要该对象可以实现__iter__方法,就可以进行迭代. 迭代对象调用__iter__方法会返 ...

  4. python之迭代器与生成器

    python之迭代器与生成器 可迭代 假如现在有一个列表,有一个int类型的12345.我们循环输出. list=[1,2,3,4,5] for i in list: print(i) for i i ...

  5. Python:迭代器的简单理解

    一.什么是迭代器 迭代,顾名思义就是重复做一些事很多次(就现在循环中做的那样).迭代器是实现了__next__()方法的对象(这个方法在调用时不需要任何参数),它是访问可迭代序列的一种方式,通常其从序 ...

  6. 第十六篇 Python之迭代器与生成器

    一.迭代器 一. 递归和迭代 生活实例说明什么是递归和迭代 A想去腾达大厦,问B怎么走路,B 说我不知道,我给你问问C,C也不知道,C又去问D,D知道,把路告诉了C,C又告诉B,B最后告诉A, 这就是 ...

  7. python——iterator迭代器|iterator详解——20140918|

    -----------------------------------------------------------------------------前言--------------------- ...

  8. 搞清楚 Python 的迭代器、可迭代对象、生成器

    很多伙伴对 Python 的迭代器.可迭代对象.生成器这几个概念有点搞不清楚,我来说说我的理解,希望对需要的朋友有所帮助. 1 迭代器协议 迭代器协议是核心,搞懂了这个,上面的几个概念也就很好理解了. ...

  9. 第五篇、Python之迭代器与生成器

    1.迭代和递归等概念 循环(loop):指的是在满足条件的情况下,重复执行同一段代码.比如,while语句,for循环. 迭代(iterate):指的是按照某种顺序逐个访问列表中的每一项.比如,for ...

随机推荐

  1. 牛客网暑期ACM多校训练营(第二场)message

    传送门:https://ac.nowcoder.com/acm/problem/16631 题意 对于直线y=ax+b,给出n个的a[i]和b[i].m次询问,每次询问给出直线y=cx+d的c[i]和 ...

  2. GPTL L3-003 社交集群(并查集)

    数据有些弱,Union函数不判不等也可以过. 题意: 依次给出 n 个人的兴趣,不同人兴趣相交.不同兴趣所属人员相交均属于同一集群,求形成的不相交集群个数及每个集群的人数. 思路: 枚举每个兴趣的人员 ...

  3. zoj2112 Dynamic Rankings (主席树 || 树套树)

    The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with t ...

  4. 【noi 2.6_6049】买书(DP)

    题意:有N元,有无限多本10.20.50和100元的书,问有几种购买方案. 解法:f[i]表示用 i 元的方案数.还有一个 j 循环这次买多少元的书. 注意--要先 j 循环,再 i 循环.因为要先考 ...

  5. Codeforces Round #663 (Div. 2) C. Cyclic Permutations (构造,图?)  

    题意:对于某个序列,若\(1\le i\le n\),\(1\le j\le i\)且\(p_j>p_i\),或者\(1\le i\le n\),\(i<j \le n\)且\(p_j&g ...

  6. C# TCP应用编程二 同步TCP应用编程

    不论是多么复杂的TCP 应用程序,双方通信的最基本前提就是客户端要先和服务器端进行TCP 连接,然后才可以在此基础上相互收发数据.由于服务器需要对多个客户端同时服务,因此程序相对复杂一些.在服务器端, ...

  7. 一篇文章图文并茂地带你轻松学完 JavaScript 闭包

    JavaScript 闭包 为了更好地理解 JavaScript 闭包,笔者将先从 JavaScript 执行上下文以及 JavaScript 作用域开始写起,如果读者对这方面已经了解了,可以直接跳过 ...

  8. 服务注册与发现-Eureka (高可用设计)

    什么是高可用 部署需要考虑的是什么: 1.系统遇到单点失效问题,如何能够快速切换到其他节点完成任务 2.如何应对网络故障,即系统如何设计成"故障开放型"(expecting fai ...

  9. Python优化机制:常量折叠

    英文:https://arpitbhayani.me/blogs/constant-folding-python 作者:arprit 译者:豌豆花下猫("Python猫"公众号作者 ...

  10. select函数详细用法解析

    1.表头文件 #include #include #include 2.函数原型 int select(int n,fd_set * readfds,fd_set * writefds,fd_set ...