1. 装饰器
- 装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
- 强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
- 装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
- 开放封闭原则:对修改封闭,对扩展开放
import time def timmer(fun): start_time=time.time() fun() end_time=time.time() def fun1(): print("in func1") timmer(fun1) #改变了原先函数的执行
-
就要用闭包来包装此函数
import time def timmer(fun): def inner(): start_time=time.time() fun() end_time=time.time() print("run in {} time {}".format(fun,end_time-start_time)) return inner #实际上是把函数名字传递给timmer,timmer执行,之所以返回inner是因为inner在全局不可以被调用 def fun1(): print("in func1") print(timmer(fun1)) #可以运行,其实就是执行Inner,目的就是在全局可以调用, fun1=timmer(fun1) #函数本身就是变量,变量值互换 fun1()
-
这样最基本的装饰器就完成了,Python为我们提供了语法糖,一个完整的装饰器如下:会允许函数传参并且返回值不变
import time def timmer(fun): def inner(*args,**kwargs): start_time=time.time() ret = fun(*args,**kwargs) end_time=time.time() print("run in {} time {}".format(fun,end_time-start_time)) return ret return inner #实际上是把函数名字传递给timmer,timmer执行,之所以返回inner是因为inner在全局不可以被调用 @timmer def fun1(num): print("in func1 {}".format(num)) return 123 # print(timmer(fun1)) #可以运行,其实就是执行Inner,目的就是在全局可以调用, # fun1=timmer(fun1) #函数本身就是变量,变量值互换 print(fun1(1))
-
这样可以修饰多个函数,但是要批量更改该怎么,如果不想装饰了,需要挨个去掉吗
import time def outer(): Flag=False def timmer(fun): def inner(*args,**kwargs): if Flag: start_time=time.time() ret = fun(*args,**kwargs) end_time=time.time() print("run in {} time {}".format(fun,end_time-start_time)) return ret else: ret = fun(*args, **kwargs) return ret return inner #实际上是把函数名字传递给timmer,timmer执行,之所以返回inner是因为inner在全局不可以被调用 return timmer @outer() #之所以加执行就是把outer的返回值timmer函数的内存地址放在这里,其实就是@timmer def fun1(num): print("in func1 {}".format(num)) return 1 @outer() def fun2(num): print("in func2 {}".format(num)) return 2 @outer() def fun3(num): print("in func3 {}".format(num)) return 3 print(fun1(1)) print(fun2(2)) print(fun3(3))
-
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
-
使用小知识点eval
login_status={"user":None,"status":False} def outer(): Flag=True def auth(func): def inner(*args,**kwargs): if Flag: with open("user.txt",encoding="utf-8") as read_f: if login_status['user'] and login_status['status']: ret = func(*args, **kwargs) return ret user_info=eval(read_f.read()) name=input("your name>>:").strip() password=input("your password>>:").strip() if name in user_info and user_info[name]["password"] == password: login_status["user"]=name login_status["status"]=True print(login_status) ret = func(*args,**kwargs) return ret else: print("bad") else: ret = func(*args, **kwargs) return ret return inner return auth @outer() def fun1(): print("in func1") return 1 @outer() def fun2(): print("in func2") return 2 @outer() def fun3(): print("in func3") return 3 fun1() fun2() fun3()
-
多个装饰器装饰同一个函数
def wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper2 @wrapper1 def f(): print('in f') f()
结果原因如下:从后分析
装饰器小练习:
#编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果 import time from urllib.request import urlopen def wrapper(func): def inner(*args,**kwargs): start_time=time.time() ret = func(*args,**kwargs).decode('utf-8') end_time=time.time() print("{} time is {}".format(*args,end_time-start_time)) return ret return inner @wrapper def get(url): return urlopen(url).read() # print(get('http://www.baidu.com')) get('http://www.baidu.com')
2. 迭代器
-
其实迭代就是我们说的,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代。
- 可迭代协议的定义非常简单,就是内部有了__iter__方法。
from collections import Iterable l = [1, 2, 3, 4] t = (1, 2, 3, 4) d = {1: 2, 3: 4} s = {1, 2, 3, 4} print(isinstance(l, Iterable)) print(isinstance(t, Iterable)) print(isinstance(d, Iterable)) print(isinstance(s, Iterable)) print(dir([1,2]))
-
用__next__也可以遍历,不依赖for循环
l=[1,2,3,4] l_iter=l.__iter__() #先把可迭代对象变成迭代器 print(l_iter.__next__()) #依次取值 print(l_iter.__next__()) #依次取值 print(l_iter.__next__()) #依次取值 print(l_iter.__next__()) #依次取值
-
while..try..
l=[1,2,3,4] l_iter=l.__iter__() #先把可迭代对象变成迭代器 # print(l_iter.__next__()) #依次取值 # print(l_iter.__next__()) #依次取值 # print(l_iter.__next__()) #依次取值 # print(l_iter.__next__()) #依次取值 while True: try: item = l_iter.__next__() print(item) except StopIteration: break
3. 生成器
-
一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值
-
但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。
-
每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
-
生成器有什么好处呢?就是不会一下子在内存中生成太多数据
def genrator_fun1(): a=1 yield a b=2 yield b g=genrator_fun1() print(next(g)) print(next(g)) #生成器监听文件输入的例子