Loading

14、迭代器协议、生成器、装饰器


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)
























posted @ 2020-02-16 16:12  云起时。  阅读(176)  评论(0编辑  收藏  举报