python基础(8)--迭代器、生成器、装饰器
1.迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
1).访问者不需要关心迭代器内部的结果,仅需要通过next()方法不断去取下一个内容
2).不能随机访问集合中的某个值,只能从头到尾依次访问
3).访问到一半时不能往回退
4).便于循环比较大的数据集合,节省内存
Python内置函数iter就是一个简单的帮助我们创造一个迭代器的内置函数。
names = iter(['a' , 'b', 'c'])
print(names)
print(names.__next__())
print(names.__next__())
print(names.__next__())
print(names.__next__()) #第一个输出打印迭代器对象
#第二三四次next方法每次都去获取迭代对象的值,每次往下取一个值,直到取完
#第五次输出 print(names.__next__())
#StopIteration,因为迭代器里面的对象已经取完了,所以出现这个异常
其实事实上,我们很少会使用__next__()方法一个一个的去取值,多数情况下都是使用for in循环进行遍历
2.生成器
一个函数调用时返回一个迭代器,这个函数就叫做生成器(generator)。如果函数中包含yield语法,那这个函数就会变成生成器
def fei(num):
x, y, z = 0, 0, 1
while x < num:
if x == 0: #当第一次循环时,返回数列0
yield y #生成器返回一个迭代对象
else: #否则返回z
yield z
y, z = z, y + z
x += 1 print(fei(9).__next__()) #只从迭代器里取一次值 for i in fei(9): #通过遍历获取迭代器内容
print(i)
生成器异步应用
import time
def consumer(name): #定义消费者函数
print("%s 准备吃包子啦!" % name) #打印消费者名字
while True:
baozi = yield #当代码运行到这里时,返回一个迭代器对象,当对象第二次调用时,会接收值并赋值给baozi
print("包子[%s]来了,被[%s]吃了!" % (baozi, name)) #打印当前使用的迭代器对象,及接收得值 def producer(*name): #定义一个生产者函数,并使用动态参数
if len(name) == 3: #当传入三个参数时,调用三次消费者函数
c = consumer(name[0])
c2 = consumer(name[1])
c3 = consumer(name[2])
c.__next__() #通过函数内置方法获取迭代器内部元素
c2.__next__()
c3.__next__()
print("老子开始准备做包子啦!")
for i in range(1, 11):
time.sleep(1)
print("做了%s个包子!" % len(name))
c.send(i) #通过迭代器方法的send属性给生成器传送值
c2.send(i)
c3.send(i) producer('alex', 'tom', 'eric') #创建一个生产者对象,并传入三个消费者名字 '''
执行结果
alex 准备吃包子啦!
tom 准备吃包子啦!
eric 准备吃包子啦!
老子开始准备做包子啦!
做了3个包子!
包子[1]来了,被[alex]吃了!
包子[1]来了,被[tom]吃了!
包子[1]来了,被[eric]吃了!
做了3个包子!
包子[2]来了,被[alex]吃了!
包子[2]来了,被[tom]吃了!
包子[2]来了,被[eric]吃了!
做了3个包子!
包子[3]来了,被[alex]吃了!
包子[3]来了,被[tom]吃了!
包子[3]来了,被[eric]吃了!
做了3个包子!
包子[4]来了,被[alex]吃了!
包子[4]来了,被[tom]吃了!
包子[4]来了,被[eric]吃了!
... '''
3.装饰器
先来了解一下函数
def func():
print('hello world') print(func) #第一次输出的是一个函数对象
print(type(func)) #第二次输出的是一个类型为函数
func() #第三次才是执行函数
print(func()) #第四次是执行函数后,并打印函数的返回结果,函数没有指定返回内容,所以是默认返回值:None
print(type(func())) #第五次也是先执行函数,再打印返回值对象的类型,可以看出,返回值对象类型是NoneType '''
第一次
<function func at 0x0000000002D771E0>
第二次
<class 'function'>
第三次
hello world
第四次
hello world
None
第五次
hello world
<class 'NoneType'> '''
以上总结出,函数不加括号是没有执行的,这时这个函数名只是一个函数对象,加括号后,函数将会执行函数体代码,最终这个函数则是函数执行完成后返回的对象
有了上面这个基础,我们再来看看装饰器
def wrapper(func):
print(func) #打印参数
return func #返回参数 @wrapper
def index():
print('hello') index() #执行顺序是,解释器从上往下读取代码
#遇到函数时,只加载定义的函数对象,并不执行函数体代码
#然后遇到装饰器@wrapper时
#解释器就会跳到这个wrapper函数
#然后执行这个wrapper函数内部代码
#通过观察可发现,这个wrapper函数一定会传入一个参数,因为测试发现,不传入一个参数,程序执行会抛出需要一个参数的异常错误
#通过分析这个参数,发现这个参数打印结果是一个函数对象
#然后wrapper函数体代码执行完毕后,继续往下执行,遇到函数index
#也是加载这个函数对象,并不执行内部函数体代码
#当遇到代码index()时,结合之前积累的函数基础知识
#这个写法实际是开始执行一个函数,所以解释器会跳到指定的index函数对象
#然后开始执行这个函数代码块
#整个执行过程结束 #执行结果
#<function index at 0x0000000002D272F0>
#hello
下面的列子具体说明装饰器的工作原理
def wrapper(func):
print(func) #打印参数
#return func`#返回参数,现在注释掉这个返回值 @wrapper
def index():
print('hello') print(type(index)) #加上一句输出类型代码语句
index() #执行结果
#<function index at 0x0000000002D972F0>
#<class 'NoneType'>
#TypeError: 'NoneType' object is not callable #首先分析下这个结果
#会不会很惊讶,只是针对上面的例子仅仅注释掉一个返回值而已,代码就不能工作了
#首先解释器还是从上往下读取代码
#遇到函数时,只加载定义函数对象,并不执行函数替代吗
#然后遇到装饰器@wrapper时
#解释器会跳到这个wrapper函数
#然后执行这个wrapper函数内部代码
#通过分析这个参数,发现这个参数打印结果是一个函数对象
#然后wrapper函数体代码执行完毕后,继续往下执行,遇到函数index
#也是只加载函数对象,并不执行内部函数体代码
#关键点来了
#代码执行到打印对象类型语句时,结果却是一个NoneType类型,根据之前对函数的基本介绍,这里的类型应该是一个函数类型才对呀
#为什么呢?命名定义了index函数,打印index类型却是NoneType类型?
#我们之前也看到只有函数没有返回值时,函数默认会返回一个None对象,故而这个对象的类型也就是NoneType类型了
#仅仅是加了一个装饰器代码@wrapper,就出现这个情况
#我们上一个例子已经说明,这个装饰器会携带一个参数,这个参数为一个函数对象
#实际上,这时候这个装饰器会对引用装饰器的函数,也就是我们这里的index函数进行重构
#所以如果我们不反悔一个函数对象时,name这个时候的index实质是一个普通的对象,不是函数类型了
#它已经被赋予None这个值了,而None不是一个函数对象,所以就没有调用方法,就不能以括号方式执行
#这是解释器督导index()这句代码,依据之前的知识,都能看出这个是取执行index这个函数内部代码快的语句
#但是执行时解释却抛了异常
#返回错误类型,TypeError: 'NoneType' object is not callable
#这个错误说明我们index执行后,是不能被调用的,只有对象类型为函数才有内置调用方法
#因为这个index已经被重构,返回值已经变成了None,也就是说index对象目前仅仅是一个普通标识符,不是函数
装饰器的高级应用
通过上面的示例可以知道,只要代码执行到装饰器标识符,都会去执行装饰器函数体,但是这个不是我们想要的,我们希望是只有我们调用引用装饰器函数时,才去执行这个装饰器函数体,那怎么办呢?我们知道,只有类型是函数对象时,代码是不会被执行,只是加载到内存而已,那装饰器函数体就可以直接返回一个函数对象
示例
def wrapper(func):
def inner():
print(func) #输出是一个函数对象
func() #这里实际是执行例子中原先定义的index函数对象的函数体
return inner @wrapper
def index():
print('hello') print(type(index))
index() #这个例子满足了需求,当我们不调用index函数时,得到的仅仅是一个函数对象,并不会执行函数代码
#当执行index函数,实际执行装饰器函数体里传入的index函数,就是执行的它本身
有参数的函数,或装饰器实现传参实例
#无参装饰器,有参函数
def wrapper(func):
def inner(name): #这个参数最终会传给这个函数体内部需要调用参数的对象
func(name) #这个参数个数是由原来函数,也就是index函数决定的
return inner @wrapper
def index(name): #传入一个参数
print('hello %s' % name) index('alex')
#无参装饰器,多参函数
def wrapper(func):
def inner(*args): #使用动态参数
func(*args)
return inner @wrapper
def index(*args): #传入一个参数
print('hello %s' % ''.join(args)) index('alex', 'eric')
#无参装饰器,多参函数2
def wrapper(func):
def inner(*args, **kwargs): #使用动态参数
func(*args, **kwargs)
return inner @wrapper
def index(*args, **kwargs):
print('hello %s'% ' '.join(args)) index('alex', 'eric')
#有参装饰器,多参函数
def one():
print('one') def two():
print('two') def func(arg1, arg2):
def wrapper(oldfunc):
def inner(*args, **kwargs):
arg1()
arg2()
oldfunc(*args, **kwargs)
return inner
return wrapper @func(one, two)
def index(*args, **kwargs):
print('hello %s' % ''.join(args)) index('alex', 'eric') #解释器遇到装饰器,由于这个装饰器是一个可执行函数
#故而先执行韩式,再次就成了我们所认知的普通装饰器了
#执行结果
#one
#two
#hello alexeric
注:本篇博客转载至博客园-曾春云的笔记,再敲一遍是为了加深印象
python基础(8)--迭代器、生成器、装饰器的更多相关文章
- Day4 - Python基础4 迭代器、装饰器、软件开发规范
Python之路,Day4 - Python基础4 (new版) 本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 ...
- Python基础4 迭代器、装饰器、软件开发规范
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...
- python中的迭代器&&生成器&&装饰器
迭代器iterator 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束. 迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外, ...
- python中的迭代器 生成器 装饰器
什么迭代器呢?它是一个带状态的对象,他能在你调用next()方法的时候返回容器中的下一个值,任何实现了__iter__和__next__()(python2中实现next())方法的对象都是迭代器,_ ...
- python基础之迭代器生成装饰器
基本概念 1.容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中.通常这类数据结构把所有的元 ...
- python基础之迭代器、装饰器、软件开发目录结构规范
生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大 ...
- Python 迭代器&生成器,装饰器,递归,算法基础:二分查找、二维数组转换,正则表达式,作业:计算器开发
本节大纲 迭代器&生成器 装饰器 基本装饰器 多参数装饰器 递归 算法基础:二分查找.二维数组转换 正则表达式 常用模块学习 作业:计算器开发 实现加减乘除及拓号优先级解析 用户输入 1 - ...
- Python基础-迭代器&生成器&装饰器
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 我现在有个需求,看 ...
- 迭代器/生成器/装饰器 /Json & pickle 数据序列化
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...
- 十一. Python基础(11)—补充: 作用域 & 装饰器
十一. Python基础(11)-补充: 作用域 & 装饰器 1 ● Python的作用域补遗 在C/C++等语言中, if语句等控制结构(control structure)会产生新的作用域 ...
随机推荐
- 【HDU5919】SequenceII(主席树)
[HDU5919]SequenceII(主席树) 题面 Vjudge 翻译(by ppl) 给一个长度为N的数列A,有m个询问,每次问 数列[l,r]区间中所有数的第一次出现的位置的中位 数是多少 题 ...
- MapReduce(一) mapreduce基础入门
一.mapreduce入门 1.什么是mapreduce 首先让我们来重温一下 hadoop 的四大组件:HDFS:分布式存储系统MapReduce:分布式计算系统YARN: hadoop 的资源调度 ...
- Qt实现截屏并保存(转载)
原博地址:http://blog.csdn.net/qinchunwuhui/article/details/52869451?_t_t_t=0.28889142944202306 目前对应用实现截屏 ...
- 洛谷P1230 智力大冲浪
题目描述 小伟报名参加中央电视台的智力大冲浪节目.本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元.先不要太高兴!因为这些钱还不一定都是你的?!接下来主持人宣布了比赛规则: ...
- Qt ------ 断开某对信号与槽的connect
QMetaObject::Connection dis; dis = connect(this,&TcpSocket::readyRead,this,&TcpSocket::readD ...
- JQ笔记-加强版
Query初级 一.介绍.基本写法 什么是JQ: 一个优秀的JS库,大型开发必备 JQ的好处: 简化JS的复杂操作 不再需要关心兼容性 提供大量实用方法 如何学习JQ: www.jquery. ...
- eclipse常用快捷键大全 (转)
Eclipse中10个最有用的快捷键组合 一个Eclipse骨灰级开发者总结了他认为最有用但又不太为人所知的快捷键组合.通过这些组合可以更加容易的浏览源代码,使得整体的开发效率和质量得到提升. ...
- Dozer 对象的"搬运工"
前言:项目中,经常会遇到各层对象之间相互进行值传递的过程,如在数据据持久层有一持久类EntityA,在视图层可能会变为ViewA,通常情况下,这两个类的属性 名称 .类型都是一致的, 在两个对象传 ...
- 机器学习-kNN-数据归一化
一.为什么需要数据归一化 不同数据之间因为单位不同,导致数值差距十分大,容易导致预测结果被某项数据主导,所以需要进行数据的归一化. 解决方案:将所有数据映射到同一尺度 二.最值归一化 normaliz ...
- Daily Report-1126
今日: 上午主要是回顾了react,阅读官方文档的时候发现了list中key值设计的必要性. 看了部分react源码,发现有些吃力,在询问羽牧学长之后调整策略,从redux和mobx入手,先多熟悉用法 ...