forth day--装饰器、迭代器、生成器

python一定会用到装饰器
 1 # 装饰器
 2 # 在原有的函数前后增加功能,且不改变原函数的调用方式
 3 
 4 # 计算一个函数的运行时间
 5 # import time
 6 # def timmer(f):
 7 #     def inner(*args,**kwargs):
 8 #         start_time = time.time()
 9 #         ret = f(*args,**kwargs)
10 #         end_time = time.time()
11 #         print(end_time - start_time)
12 #         return ret
13 #     return inner
14 #
15 # @timmer   # func = timmer(func)
16 # def func(a,b):
17 #     print('begin func',a)
18 #     time.sleep(0.1)
19 #     print('end func',b)
20 #     return True
21 #
22 # ret = func(1,2)   #--> inner()
23 
24 
25 # def timmer(f):
26 #     def inner(*args,**kwargs):
27 #
28 #         ret = f(*args,**kwargs)
29 #
30 #         return ret
31 #     return inner
装饰器初识

1.装饰器的进阶
1.设计装饰器确认是否生效 定义一个装饰器传参数
outer()
 1 # 进阶的需求
 2 # 第一种情况
 3 #     500个函数
 4 #     你可以设计你的装饰器 来确认是否生效
 5 
 6 # import time
 7 # FLAG = True
 8 # def outer(flag):
 9 #     def timmer(f):
10 #         def inner(*args,**kwargs):
11 #             if flag == True:
12 #                 start_time = time.time()
13 #                 ret = f(*args,**kwargs)
14 #                 end_time = time.time()
15 #                 print(end_time - start_time)
16 #             else:
17 #                 ret = f(*args, **kwargs)
18 #             return ret
19 #         return inner
20 #     return timmer
21 #
22 # @outer(FLAG)   # func = timmer(func)
23 # def func(a,b):
24 #     print('begin func',a)
25 #     time.sleep(0.1)
26 #     print('end func',b)
27 #     return True
28 #
29 # func(1,2)
往装饰器中传参数

2.装饰器 登录 记录日志
 1 # 第二种情况
 2 def wrapper1(func):
 3     def inner1():
 4         print('wrapper1 ,before func')
 5         func()
 6         print('wrapper1 ,after func')
 7     return inner1
 8 
 9 def wrapper2(func):
10     def inner2():
11         print('wrapper2 ,before func')
12         func()
13         print('wrapper2 ,after func')
14     return inner2
15 
16 @wrapper2
17 @wrapper1
18 def f():
19     print('in f')
20 
21 # f()
多个装饰器装饰一个函数小例子

自动登录!@login 单点登录(不加timer时)

登录,计算index和manager执行时间 :在写一个装饰器timer
多个装饰器,从下开始执行
 1 # 装饰器 登录 记录日志
 2 import time
 3 login_info = {'alex':False}
 4 def login(func):   # manager
 5     def inner(name):
 6         if login_info[name] != True:
 7             user = input('user :')
 8             pwd = input('pwd :')
 9             if user == 'alex' and pwd == 'alex3714':
10                 login_info[name] = True
11         if login_info[name] == True:
12             ret = func(name)     # timmer中的inner
13             return ret
14     return inner
15 
16 def timmer(f):
17     def inner(*args,**kwargs):
18         start_time = time.time()
19         ret = f(*args,**kwargs)     # 调用被装饰的方法
20         end_time = time.time()      #
21         print(end_time - start_time)
22         return ret
23     return inner
24 
25 @login
26 @timmer
27 def index(name):
28     print('欢迎%s来到博客园首页~'%name)
29 
30 @login
31 @timmer    # manager = login(manager)
32 def manager(name):
33     print('欢迎%s来到博客园管理页~'%name)
34 
35 index('alex')
36 index('alex')
37 manager('alex')
38 manager('alex')
39 
40 # 计算index 和 manager的执行时间
登录计算时间
2.迭代器
从列表中取值
可迭代的
可迭代协议:__iter__方法
迭代器协议:__iter__和__next__方法

iter
while True
try---except异常处理
迭代器节省内存,快 iterable 可迭代的 iterator迭代器
py2 range
py3 range
迭代器特性:惰性运算
小例子
for line in f:(f至少是可迭代的)
列表字典 元祖字符串 集合 range 文件句柄 enumerate
 1 # 迭代器
 2 # 如何从列表、字典中取值的
 3     # index索引 ,key
 4     # for循环
 5 # 凡是可以使用for循环取值的都是可迭代的
 6 # 可迭代协议 :内部含有__iter__方法的都是可迭代的
 7 # 迭代器协议 :内部含有__iter__方法和__next__方法的都是迭代器
 8 # print(dir([1,2,3]))
 9 # lst_iter = [1,2,3].__iter__()
10 # print(lst_iter.__next__())
11 # print(lst_iter.__next__())
12 # print(lst_iter.__next__())
13 # for i in [1,2,3]:   #  [1,2,3].__iter__()
14 #     print(i)
15 # l = [1,2,3]
16 # lst_iter = iter(l)   # l.__iter__()
17 # while True:
18 #     try:
19 #         print(next(lst_iter)) # lst_iter.__next__()
20 #     except StopIteration:
21 #         break
22 
23 # 什么是可迭代的
24 # 什么是迭代器     迭代器 = iter(可迭代的),自带一个__next__方法
25 # 可迭代 最大的优势 节省内存
26 # from collections import Iterable,Iterator
27 # print(range(100000000))            #range(0, 100000000)
28 # print(isinstance(range(100000000),Iterable))   #True
29 # print(isinstance(range(100000000),Iterator))    #False
30 # py2 range 不管range多少 会生成一个列表 这个列表将用来存储所有的值
31 # py3 range 不管range多少 都不会实际的生成任何一个值
32 # 迭代器的优势:
33 #     节省内存
34 #     取一个值就能进行接下来的计算 ,而不需要等到所有的值都计算出来才开始接下来的运算 —— 快
35 # 迭代器的特性:惰性运算
36 
37 # f = open()
38 # for line in f:
39 
40 # 列表 字典 元组 字符串 集合 range 文件句柄 enumerate
讲课笔记
3.生成器generator
自己写的迭代器 就是一个生成器
两种自己写生成器(迭代器)的机制:生成器函数 生成器表达式
做衣服的例子 2000000 分批取
# 200 0000
# 牛翔  200 0000
# 40期
# 赵英杰 200 0000
# 21 60  60件衣服
# 200 0000 - 60
# 500期  0
# 501

# def cloth(num):
#     ret = []
#     for i in range(num):
#         ret.append('cloth%s'%i)
#     return ret
View Code

yield凡是带有yield的函数就是生成器函数
生成器函数的调用不会触发代码的执行,而是返回一个生成器(迭代器) 加next取值
yield记录当前位置,等下一个next触发
 1 # 凡是带有yield的函数就是一个生成器函数
 2 # def func():
 3 #     print('****')
 4 #     yield 1
 5 #     print('^^^^')
 6 #     yield 2   # 记录当前所在的位置,等待下一次next来触发函数的状态
 7 #
 8 # g = func()
 9 # print('--',next(g))   #****
10                         #-- 1
11 # print('--',next(g))    #^^^^
12                         #-- 2
13 # 生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
14 # 想要生成器函数执行,需要用next
15 # def cloth_g(num):
16 #     for i in range(num):
17 #         yield 'cloth%s'%i
18 #
19 # g = cloth_g(1000)
20 # print(next(g))    #cloth0
21 # print(next(g))    #cloth1
22 # print(next(g))    #cloth2
概念+next

生成器函数
多个next例子
使用生成器监听文件输入的例子,图片未保存看视频! 写入文件需要保存(无法用函数去做,函数无法监听)----实现记录日志
mac本中关闭文件才认为保存。
 1 # 使用生成器监听文件输入的例子
 2 # import time
 3 # def listen_file():
 4 #     with open('userinfo') as f:
 5 #         while True:
 6 #             line = f.readline()
 7 #             if line.strip():
 8 #                 yield line.strip()
 9 #             time.sleep(0.1)
10 #
11 # g = listen_file()
12 # for line in g:
13 #     print(line)
使用生成器监听文件输入的例子

send关键字:例子
定义:在执行next的过程中 传递一个参数 给生成器函数的内部
分析执行图片
向内部传参
send 不能用在第一次传值,必须next;send传给yield后的返回值
 1 # send关键字
 2 # def func():
 3 #     print(11111)
 4 #     ret1 = yield 1
 5 #     print(22222,'ret1 :',ret1)
 6 #     ret2 = yield 2
 7 #     print(33333,'ret2 :',ret2)
 8 #     yield 3
 9 #
10 # g = func()
11 # ret = next(g)
12 # print(ret)
13 # print(g.send('alex'))  # 在执行next的过程中 传递一个参数 给生成器函数的内部
14 # print(g.send('金老板'))
15 # 想生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器
send概念

#例子 计算移动平均值!!
月度的天平均收入 def average():
注意开始day=0报错的处理 分析图片
 1 # 例子
 2 # 计算移动平均值
 3 # 12 13 15 18
 4 # 月度 的 天平均收入
 5 # def average():
 6 #     sum_money = 0
 7 #     day = 0
 8 #     avg = 0
 9 #     while True:
10 #         money = yield avg
11 #         sum_money += money
12 #         day += 1
13 #         avg = sum_money/day
14 #
15 # g = average()
16 # next(g)
17 # print(g.send(200))
18 # print(g.send(300))
19 # print(g.send(600))
例子--月度 的 天平均收入

预激生成器 next(g) 放在装饰器中 看思考题面试最后一道
 1 # 预激生成器
 2 # def init(func):
 3 #     def inner(*args,**kwargs):
 4 #         ret = func(*args,**kwargs)
 5 #         next(ret)  # 预激活
 6 #         return ret
 7 #     return inner
 8 #
 9 # @init
10 # def average():
11 #     sum_money = 0
12 #     day = 0
13 #     avg = 0
14 #     while True:
15 #         money = yield avg
16 #         sum_money += money
17 #         day += 1
18 #         avg = sum_money/day
19 #
20 # g = average()
21 # print(g.send(200))
22 # print(g.send(300))
23 # print(g.send(600))
预激生成器-天平均例子加装饰器预激活

yield from
例子 range从0开始取值
yield from range(5) ---->
for i in range(5):
print(i)
g=generator_func() 与放print中区别,放在print中一直打印0
g取得不同的内存
 1 # yield from
 2 def generator_func():
 3     yield from range(5)
 4     yield from 'hello'
 5     # for i in range(5):
 6     #     yield i
 7     # for j in 'hello':
 8     #     yield j
 9 
10 # g = generator_func()
11 # for i in generator_func():
12 #     print(i)
13 
14 # g1 = generator_func()
15 # g2 = generator_func()
16 # next(generator_func())
17 # next(generator_func())
yield from

如何从生成器取值
next :随时停止,最后一次会报错,不知道在哪儿停
for循环:从头到尾遍历一次,不遇到break、return不停止
list、tuple:把所有数据类型都放在list中,浪费内存
# 如何从生成器中取值
# 第一种 :next  随时都可以停止 最后一次会报错
# print(next(g))
# print(next(g))
# 第二种 :for循环 从头到尾遍历一次 不遇到break、return不会停止
# for i in g:
#     print(i)
# 第三种 :list tuple 数据类型的强转  会把所有的数据都加载到内存里 非常的浪费内存
# print(g)
# print(list(g))
View Code

总结:有yield。。。
生成器用途2个图片
1 # 生成器函数 是我们python程序员实现迭代器的一种手段
2 # 主要特征是 在函数中 含有yield
3 # 调用一个生成器函数 不会执行这个函数中的带码 只是会获得一个生成器(迭代器)
4 # 只有从生成器中取值的时候,才会执行函数内部的带码,且每获取一个数据才执行得到这个数据的带码
5 # 获取数据的方式包括 next send 循环 数据类型的强制转化
6 # yield返回值的简便方法,如果本身就是循环一个可迭代的,且要把可迭代数据中的每一个元素都返回 可以用yield from
7 # 使用send的时候,在生成器创造出来之后需要进行预激,这一步可以使用装饰器完成
8 # 生成器的特点 : 节省内存 惰性运算
9 # 生成器用来解决 内存问题 和程序功能之间的解耦
小结


生成器表达式
推导过程例子
完整的列表推导式
#30以内能被3整除的数
print([i for i in range(30) if i%3==0])
#30以内能被3整除的数的平方
print([i**2 for i in range(30) if i%3==0])
两个for也可以
研究集合、字典推导式---不常用
 1 # 列表推倒式
 2 # new_lst = []
 3 # for i in range(10):
 4 #     new_lst.append(i**2)
 5 # print(new_lst)
 6 # print([i**2 for i in range(10)])
 7 # l = [1,2,3,-5,6,20,-7]
 8 # print([i%2 for i in range(10)])
 9 # l = [1,2,3,-5,6,20,-7]
10 # print([num for num in l if num%2 == 1])
11 
12 # 30以内所有能被3整除的数
13 # print([i for i in range(30) if i%3 ==0])
14 #
15 # 30以内所有能被3整除的数的平方
16 # print([i**2 for i in range(30) if i%3 ==0])
17 
18 # 找到嵌套列表中名字含有两个‘e’的所有名字
19 # names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
20 #          ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
21 # print([name for name_lst in names for name in name_lst if name.count('e') == 2])
列表推导式
 
     列表推导式[] 排序的时候
        生成器表达式()   数据量庞大的时候用
1 # 生成器表达式
2 # l = [i for i in range(30) if i%3 ==0]   # 列表推倒式 排序的时候
3 # g = (i for i in range(30) if i%3 ==0)   # 生成器表达式 庞大数据量的时候 使用生成器表达式
4 # print(l)
5 # print(g)
6 # for i in g:print(i)
对比

面试题
1.list时真正执行  一个生成器只能取一次
 1 # def demo():
 2 #     for i in range(4):
 3 #         yield i
 4 #
 5 # g=demo()
 6 #
 7 # g1=(i for i in g)
 8 # g2=(i for i in g1)
 9 #
10 # print(list(g1))   #[0,1,2,3]
11 # print(list(g2))   #[]
1
2.[20,21,22,23]重点理解生成器什么时候执行!!
生成器在不找它要值的时候始终不执行
执行时候,要以执行变量值为准
[1,3,10] [30,31,32,33]
 1 # mianshiti2
 2 # def add(n,i):
 3 #     return n+i
 4 #
 5 # def test():
 6 #     for i in range(4):
 7 #         yield i
 8 #
 9 # g=test()
10 # for n in [1,10]:
11 #     g=(add(n,i) for i in g)
12 #
13 # print(list(g))
2

3.面试题3,看懂即可!
 1 import os
 2 
 3 def init(func):
 4     def wrapper(*args,**kwargs):
 5         g=func(*args,**kwargs)
 6         next(g)
 7         return g
 8     return wrapper
 9 
10 @init
11 def list_files(target):
12     while 1:
13         dir_to_search=yield
14         for top_dir,dir,files in os.walk(dir_to_search):
15             for file in files:
16                 target.send(os.path.join(top_dir,file))
17 @init
18 def opener(target):
19     while 1:
20         file=yield
21         fn=open(file)
22         target.send((file,fn))
23 @init
24 def cat(target):
25     while 1:
26         file,fn=yield
27         for line in fn:
28             target.send((file,line))
29 
30 @init
31 def grep(pattern,target):
32     while 1:
33         file,line=yield
34         if pattern in line:
35             target.send(file)
36 @init
37 def printer():
38     while 1:
39         file=yield
40         if file:
41             print(file)
42 
43 g=list_files(opener(cat(grep('python',printer()))))
44 
45 g.send('/test1')
46 
47 协程应用:grep -rl /dir
tail&grep
 

猜你喜欢

转载自www.cnblogs.com/lijie123/p/8922145.html