14.1、迭代器协议:
1、迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回对象中的下一项,要么就引起一个StopIteration异常,以终止次迭
代,迭代器协议规定迭代只能往后走,不能往前退;
2、可迭代对象是指:实现了迭代器协议的对象,可迭代对象只能遍历一次,使用可迭代对象比较省内存空间,通常使用__iter__和__next__实现;
3、协议是一种约定,可迭代对象实现了迭代器协议,python内部工具(如:for,sum,min,max函数等)使用迭代器协议访问可迭代对象;
4、字符串,列表,元组,字典,集合,文件对象、这些都不是可迭代对象,只不过for循环调用了他们内部的__iter__()方法,把他们变成了
可迭代对象;
5、可迭代对象用法:
(1)查看函数可用的方法:
print(dir(set))
(2)示例:
1)
x='hello'
iter_test=x.__iter__()
# 遵循迭代器协议,生成可迭代对象
print(iter_test)
# <str_iterator object at 0x00000182D0132EB8>
# 输出的是可迭代对象
print(iter_test.__next__())
print(next(iter_test))
# next(iter_test)---->iter_test.__next__()
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
# print(iter_test.__next__())
# 如果超过迭代的元素会引起StopIteration异常
2)
l=[1,2,3,4,5]
diedai_l=l.__iter__()
while True:
try:
print(diedai_l.__next__())
except StopIteration:
print('迭代完毕了,循环终止了')
break
3)
dic={'a':1,'b':2}
iter_d=dic.__iter__()
print(iter_d.__next__())
print(iter_d.__next__())
4)
f=open('告白气球','r',encoding='utf8')
iter_f=f.__iter__()
print(iter_f)
# <_io.TextIOWrapper name='告白气球' mode='r+' encoding='utf8'>
print(iter_f.__next__(),end='')
print(iter_f.__next__(),end='')
5)
f=open('告白气球','r',encoding='utf8')
for i in f:
print(i,end='')
6)
l = [1, 2]
print(sum(l))
# sum(l.__iter__().next+l.__iter__().next)
7)最终写法:
l=[1,2,3]
for i in l: #i_l=l.__iter_() i=i_l.__next__()
print(i)
14.2、生成器:
1、生成器可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其它的数据类型需要调用自己内置的__iter__()方法来实现迭代器协
议)所以生成器就是可迭代对象;
2、语法上和函数类似:生成器函数和常规函数几乎是一样的,它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,
而常规函数使用return语句返回一个值;
3、自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数),由于生成器自动实现
了迭代器协议,所以,我们可以调用它的next方法,并且在没有值可以返回的时候,生成器自动产生StopIteration异常;
4、状态挂起:生成器使用yield语句返回一个值,yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行;
5、注意事项:生成器只能遍历一次
6、使用生成器的优点:
(1)优点一:生成器的好处是延迟计算,一次返回一个结果,也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用;
#列表解析
sum([i for i in range(100000000)]) #内存占用大,机器容易卡死
#生成器表达式
sum(i for i in range(100000000)) #几乎不占内存
(2)优点二:生成器还能有效提高代码可读性
7、生成器的用法:
(1)普通用法:
def test():
yield 1
yield 2
yield 3
g = test()
# 获取生成器对象
print(g)
# <generator object test at 0x0000025B4D0C97C8>
print(g.__next__())
print(g.__next__())
print(g.__next__())
(2)使用三元表达式创建生成器:
1)三元表达的使用(三元表达式只有三元,没有四元):
name = 'chang'
res = 'cool' if name == 'chang' else 'so cool'
print(res)
test = [i for i in range(10) if i > 5]
print(test)
test_list = []
for i in range(10):
test_list.append(i)
print(test_list)
#等价于
l = [i for i in range(10)]
print(l)
2)示例:
laomuji = ('鸡蛋%s' % i for i in range(5))
# 生成器表达式
print(laomuji)
# <generator object <genexpr> at 0x0000022CA82A97C8>
print(laomuji.__next__())
print(laomuji.__next__())
print(next(laomuji))
print(next(laomuji))
print(next(laomuji))
#等价于
laomuji = ('鸡蛋%s' % i for i in range(5))
for i in laomuji:
print("鸡蛋%s" %i)
14.3、装饰器:
1、装饰器定义:本质就是函数,功能是为其他函数添加新功能
2、装饰器需要遵循的原则:
(1)不修改被装饰函数的源代码
(2)为被装饰函数添加新功能后,不修改被修饰函数的调用方式
3、实现装饰器知识储备:
装饰器=高阶函数+函数嵌套+闭包( 在一个作用域里放入定义变量,相当于打了一个包)
4、装饰器的用法:
import time
def timmer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
# 运行的是cal函数
stop_time = time.time()
print('函数运行时间是%s' % (stop_time - start_time))
return res
return wrapper
@timmer
# 语法糖@
# @timmer就相当于cal=timmer(cal),返回的是wrapper的地址,执行cal()就是在执行wrapper()
# cal=timmer(cal)=wrapper
def cal(l):
res = 0
for i in l:
time.sleep(0.1)
res += i
return res
res = cal(range(20))
print(res)