python进阶之生成器
迭代器
什么叫迭代
可以被for循环的就说明他们是可迭代的,比如:字符串,列表,字典,元祖,们都可以for循环获取里面的数据
下面我们看一个代码:
number = 12345
for i in number:
print(i)
输出:
Traceback (most recent call last):
File "D:**.py", line 272, in <module>
for i in number:
TypeError: 'int' object is not iterable
报错信息是说:int类型不可迭代,不能使用循环取每个数据。 那么我们又怎么说 字符串,列表,字典,元祖是可迭代的呢?
from collections import Iterable l = [1, 2, 3, 4]
t = (1, 2, 3, 4)
d = {1: 2, 3: 4}
s = {1, 2, 3, 4} print(isinstance(l, Iterable)) # 判断是否是可迭代
print(isinstance(t, Iterable))
print(isinstance(d, Iterable))
print(isinstance(s, Iterable))
True
True
True
True
再从字面上理解一下,其实迭代就是我们刚刚说的,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代。
什么叫可迭代协议
我们现在是从结果分析原因,能被for循环的就是“可迭代的”,但是如果正着想,for怎么知道谁是可迭代的呢?
假如我们自己写了一个数据类型,希望这个数据类型里的东西也可以使用for被一个一个的取出来,那我们就必须满足for的要求。这个要求就叫做“协议”。
可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了__iter__方法。
print(dir([1,2]))
print(dir((1,1)))
print(dir({1:2}))
print(dir({1,2}))
输出:
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']
现在我们可以知道:可以被for循环的都是可迭代的,要想迭代内部必须有一个__iter__方法。
那么这个方法又干了些什么事情呢?
print([1,2].__iter__()) 结果
<list_iterator object at 0x1024784a8>
看结果,应该是得到了一个可迭代对象list_iterator 就是一个迭代器,现在我们知道这个列表有一个迭代器了
print(set(dir([1,2].__iter__()))-set(dir([1,2]))) 输出:
{'__next__', '__setstate__', '__length_hint__'}
我们获取了列表迭代器3个方法,那么这些方法又干了什么呢? 我们只说__next__
iter = [1,2,3,4,5,6].__iter__() #一个一个的取值
print(iter.__next__())
print(iter.__next__())
输出:
1
2
我们看到的结果是取到了列表的前两个元素,所以说,for循环就是调用了内部的__next__方法实现遍历的,我们可以不使用for循环,直接调用这个方法就可以实现遍历列表元素
但是如果我们列表有3个元素我们调用__next__4次就会抛出异常StopIteration,因为没有第4个元素
iter = [1,2,3].__iter__() #一个一个的取值
print(iter.__next__())
print(iter.__next__())
print(iter.__next__())
print(iter.__next__())
输出:
Traceback (most recent call last):
1
File "D:/pythonSeleniumTestCode/pythonStu/python练习100例.py", line 295, in <module>
2
print(iter.__next__())
3
StopIteration
现在我们把这个异常处理一下
iter = [1,2,3].__iter__()
while 1:
try:
item = iter.__next__()
print(item)
except StopIteration:
break
那现在我们就使用while循环实现了原本for循环做的事情,我们是从谁那儿获取一个一个的值呀?是不是就是l_iter?好了,这个l_iter就是一个迭代器。
迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。
现在我们已经大概有了迭代器的印象,那么我们再来看看生成器是个什么鬼!
生成器
我们知道的迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。
如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器
Python中提供的生成器
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
生成器Generator
本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
特点:惰性运算,开发者自定义
看实例代码:
def genrator():
for i in range(1, 5):
yield ('正在生成数字{}'.format(i)) # yie = genrator()
for i in yie:
print(i)
输出:
正在生成数字1
正在生成数字2
正在生成数字3
正在生成数字4
如果我只想生成2个数字我们该怎么实现呢?是不是这样?
yie = genrator()
num = 0
for i in yie:
print(i)
num+=1
if num == 2:
break
输出:
正在生成数字1
正在生成数字2
现在们已经生成了2个数字了,那么我想接着生成,还可不可以呢?
def genrator():
for i in range(1, 5):
yield ('正在生成数字{}'.format(i)) yie = genrator()
num = 0
for i in yie:
print(i)
num+=1
if num == 2:
print('我只能生成2个数')
break
for i in yie:
print(i)
输出:
正在生成数字1
正在生成数字2
我只能生成2个数
正在生成数字3
正在生成数字4
结果我们分析出,生成2个数以后既然还可以接着原来的生成。
下面我们再来看看到底怎么使用生成器,我现在要监听一个文件的输入,如果文件中增加了数据,我就在控制到输出增加的内容
import time def tail(filename):
f = open(filename)
f.seek(0, 2) #从文件末尾算起
while True:
line = f.readline() # 读取文件中新的文本行
if not line:
time.sleep(0.1)
continue
yield line tail_g = tail('tmp.txt')
for line in tail_g:
print(line)
只要我再A文件中写入一行数据,那么控制到就会输出这行数据,我们就达到了监听文件的作用,是不是还挺好用的!
结论
生成器好处
1.不会占用太多的内存,我们需要生成一个数就生成,不需要就不用叫他生成
2.延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。
什么是生成器
只要含有yield关键字的函数都是生成器函数, 且yield不能与return一起使用,二者存一,而且只能写在函数的内部
python进阶之生成器的更多相关文章
- Python进阶(四)----生成器、列表推导式、生成器推导式、匿名函数和内置函数
		Python进阶(四)----生成器.列表推导式.生成器推导式.匿名函数和内置函数 一丶生成器 本质:  就是迭代器 生成器产生的方式:  1.生成器函数 
- Python 进阶_生成器 & 生成器表达式
		目录 目录 相关知识点 生成器 生成器 fab 的执行过程 生成器和迭代器的区别 生成器的优势 加强的生成器特性 生成器表达式 生成器表达式样例 小结 相关知识点 Python 进阶_迭代器 & ... 
- Python进阶-VI 生成器函数进阶、生成器表达式、推导式
		一.生成器函数进阶 需求:求取移动平均数 1.应用场景之一,在奥运会气枪射击比赛中,每打完一发都会显示平均环数! def show_avg(): print('你已进入显示移动平均环数系统!') a ... 
- 十三. Python基础(13)--生成器进阶
		十三. Python基础(13)--生成器进阶 1 ● send()方法 generator.send(value) Resumes the execution, and "sends&qu ... 
- Python进阶:函数式编程实例(附代码)
		Python进阶:函数式编程实例(附代码) 上篇文章"几个小例子告诉你, 一行Python代码能干哪些事 -- 知乎专栏"中用到了一些列表解析.生成器.map.filter.lam ... 
- Python进阶 - 命名空间与作用域
		Python进阶 - 命名空间与作用域 写在前面 如非特别说明,下文均基于Python3 命名空间与作用于跟名字的绑定相关性很大,可以结合另一篇介绍Python名字.对象及其绑定的文章. 1. 命名空 ... 
- Python进阶5---StringIO和BytesIO、路径操作、OS模块、shutil模块
		StringIO StringIO操作 BytesIO BytesIO操作 file-like对象 路径操作 路径操作模块 3.4版本之前:os.path模块 3.4版本开始 建议使用pathlib模 ... 
- python进阶篇
		python进阶篇 import 导入模块 sys.path:获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到.  import sys ... 
- [Book Content]Python进阶
		python进阶 原书内容https://github.com/eastlakeside/interpy-zh 通过记录书本目录和大概内容做一个记录,方便以后回顾检索. Chapter Title B ... 
随机推荐
- Postman 安装
			前言 安装前的准备: 1.Chrome 浏览器的扩展插件来进行的安装,并非单独应用程序. 2.电脑上已经安装了 Chrome 浏览器 3.本文章适用操作系统 window7 一,非官方安装 个人不建 ... 
- 暖春许愿季丨i春秋给你送福利
			没有一点点防备 也没有一丝顾虑 就这样出现——暖春许愿季 纳尼?这不是我的歌声里 是i春秋在搞活动 这次准备搞个大的 多大呢 看这里 你许下心愿 我帮你实现 这是一棵神奇的心愿树 是一个畅所欲言之地 ... 
- 每日分享!介绍Css 盒模型!
			如何定义盒模型: 在CSS盒子模型理论中,页面中所有的元素都是看成一个盒子,并且还占据一定的空间. 一个页面是由很多这样的盒子组成的.这些盒子之间都会相会影响,因此我们掌握CSS盒模型相当重要.需要理 ... 
- JS正则表达式匹配域名 网址 URL
			DNS规定,域名中的标号都由英文字母和数字组成,每一个标号不超过63个字符,也不区分大小写字母.标号中除连字符(-)外不能使用其他的标点符号.级别最低的域名写在最左边,而级别最高的域名写在最右边.由多 ... 
- java常用API的总结(1)
			本篇是对于这一段时间以来接触到的常用api的一些总结,便于以后的查阅.... 一.正则表达式 对于正则表达式,我的感觉就是当我们在做某些题的时候正则表达式会省去我们很多的时间,并且正则表达式的使用格式 ... 
- Xapian索引-文档检索过程分析之匹配百分比
			本文属于文档检索过程分析的一部分,重点分析文档匹配百分比(percent)的计算过程. 1 percent是什么? 我们之前分析的检索demo: Xapian::Query term_one = Xa ... 
- k.tt 研究下生成的逻辑代码:从壹开始前后端分离 [.netCore 填坑 ] 三十二║ 四种方法快速实现项目的半自动化搭建
			更新 1.更新小伙伴 @大龄Giser 提出好点子:试试VS的插件扩展:VSIX.ItemProject等,将T4模板给制作插件,这里先记下,有懂的小伙伴可以自己先试试,我会在以后更新. 2.感谢小伙 ... 
- Spring Cloud实战的代码和视频位置
			大家好,本博文的连接里包含了Spring Cloud实战的代码和视频位置. 代码下载连接: 视频下载连接: 
- 【hashMap】详谈
			官方文档地说明 几个关键的信息:基于Map接口实现.允许null键/值.非同步.不保证有序(比如插入的顺序).也不保证序不随时间变化. 一.概述 HashMap 是一个散列表,它存储的内容是键值对(k ... 
- Floyd算法java实现demo
			Floyd算法java实现,如下: https://www.cnblogs.com/Halburt/p/10756572.html package a; /** * ┏┓ ┏┓+ + * ┏┛┻━━━ ... 
