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
1 def add(n,i):
2 return n+i
3
4 def test():
5 for i in range(4):
6 yield i
7
8 g=test()
9 # for n in [1,10]:
10 # g=(add(n,i) for i in g)
11 # n=1
12 # g=(add(n,i) for i in g)
13 n=10
14 #g = (add(n, i) for i in add(n,i) for i in test())
15 # g = (add(10, i) for i in add(10,i) for i in [0,1,2,3])
16 g = (add(10, i) for i in [10,11,1213])
17 print(list(g)) [20,21,22,23]
详解
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