当前位置:
首页 > temp > python入门教程 >
-
python--高级语法 9
day14:
1、开放封闭原则:
装饰器:装饰,装修,房子就可以住,如果装修,不影响你住,而且体验更加,让你生活中增加了很多功能:洗澡,看电视,沙发。
器:工具。
开放封闭原则:
开放:对代码的拓展开放的, 更新地图,加新枪,等等。
封闭:对源码的修改是封闭的。闪躲用q。就是一个功能,一个函数。 别人赤手空拳打你,用机枪扫你,扔雷.....这个功能不会改变。
装饰器:完全遵循开放封闭原则。
所以装饰器最终最完美的定义就是: 在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。
装饰器就是一个函数。(装饰器就是一个闭包)
2、装饰器的初识:
-
版本一: Mike 写一些代码,测试一下index()函数的执行效率。
# import time #print(time.time()) # 格林威治时间。 def index(): '''有很多代码.....''' time.sleep(2) # 模拟的网络延迟或者代码效率 print('欢迎登录博客园首页') def dariy(): '''有很多代码.....''' time.sleep(3) # 模拟的网络延迟或者代码效率 print('欢迎登录日记页面') start_time=time.time() index() end_time=time.time() print(end_time-start_time) start_time=time.time() dariy() end_time=time.time() print(end_time-start_time) 欢迎登录博客园首页 2.0008764266967773 欢迎登录日记页面 3.0002834796905518 Process finished with exit code 0
版本一的问题:如果测试别人的代码,必须重新复制粘贴。
-
版本二:利用函数,解决代码重复使用的问题(解决版本一问题)
#版本二:利用函数,解决代码重复使用的问题(解决版本一问题) import time def index(): '''有很多代码.....''' time.sleep(2) # 模拟的网络延迟或者代码效率 print('欢迎登录博客园首页') def dariy(): '''有很多代码.....''' time.sleep(3) # 模拟的网络延迟或者代码效率 print('欢迎登录日记页面') def timmer(f): start_time = time.time() f() end_time = time.time() print(f'测试本函数的执行效率:{end_time-start_time}') timmer(index) #版本二还是有问题: 原来index函数源码没有变化,给原函数添加了一个新的功能测试原函数的执行效率的功能。 #满足开放封闭原则么?原函数的调用方式改变了。 欢迎登录博客园首页 测试本函数的执行效率:2.0008556842803955 Process finished with exit code 0
-
版本三:不能改变原函数的调用方式。
#版本三:不能改变原函数的调用方式。 import time def index(): '''有很多代码.....''' time.sleep(2) # 模拟的网络延迟或者代码效率 print('欢迎登录博客园首页') def timmer(f): # f = index (funciton index123) def inner(): # inner :(funciton inner123) start_time = time.time() f() #index() (funciton index123) end_time = time.time() print(f'测试本函数的执行效率:{end_time-start_time}') return inner # (funciton inner123) # ret=timmer(index) # ret() #相当于inner() index=timmer(index) # inner (funciton inner123) index() # inner()
-
版本四:具体研究(装饰器的本质就是闭包)
import time def index(): '''有很多代码.....''' time.sleep(2) # 模拟的网络延迟或者代码效率 print('欢迎登录博客园首页') def timmer(f): f = index # f = <function index at 0x0000023BA3E8A268> def inner(): start_time = time.time() f() end_time = time.time() print(f'测试本函数的执行效率{end_time-start_time}') return inner index = timmer(index) index()
-
版本五:python做了一个优化;提出了一个语法糖的概念。 标准版的装饰器
(@timmer #等于index = timmer(index))
#版本五:python做了一个优化;提出了一个语法糖的概念。 标准版的装饰器 import time #timmer装饰器 def timmer(f): def inner(): start_time = time.time() f() end_time = time.time() print(f'测试本函数的执行效率:{end_time-start_time}') return inner @timmer #等于index = timmer(index) def index(): '''有很多代码.....''' time.sleep(2) # 模拟的网络延迟或者代码效率 print('欢迎登录博客园首页') @timmer def dariy(): '''有很多代码.....''' time.sleep(3) # 模拟的网络延迟或者代码效率 print('欢迎登录日记页面') # index = timmer(index) # index() # # dariy = timmer(dariy) # dariy() index() dariy()
-
版本六:被装饰函数带返回值
#版本六:被装饰函数带返回值 import time #timmer装饰器 def timmer(f): def inner(): start_time = time.time() r=f() #print(f'这个是f():{f()}!!!') end_time = time.time() print(f'测试本函数的执行效率:{end_time-start_time}') return r return inner @timmer #等于index = timmer(index) def index(): '''有很多代码.....''' time.sleep(0.6) # 模拟的网络延迟或者代码效率 print('欢迎登录博客园首页') return 666 # 加上装饰器不应该改变原函数的返回值,所以666 应该返回给我下面的ret, # 但是下面的这个ret实际接收的是inner函数的返回值,而666返回给的是装饰器里面的 # f() 也就是 r,我们现在要解决的问题就是将r给inner的返回值。 ret=index() print(ret) 欢迎登录博客园首页 测试本函数的执行效率:0.6006889343261719 666 Process finished with exit code 0
-
版本七:被装饰函数带参数
#版本七:被装饰函数带参数 import time #timmer装饰器 def timmer(f): def inner(*args,**kwargs): # 函数的定义:* 聚合 args = ('李舒淇',18) start_time = time.time() r=f(*args,**kwargs) # 函数的执行:* 打散:f(*args) --> f(*('李舒淇',18)) --> f('李舒淇',18) #print(f'这个是f():{f()}!!!') end_time = time.time() print(f'测试本函数的执行效率:{end_time-start_time}') return r return inner @timmer def index(name): '''有很多代码.....''' time.sleep(0.6) # 模拟的网络延迟或者代码效率 print(f'欢迎{name}登录博客园首页') return 666 @timmer def dariy(name,age): '''有很多代码.....''' time.sleep(0.5) # 模拟的网络延迟或者代码效率 print(f'欢迎{age}岁{name}登录日记页面') dariy('李舒淇',18) # inner('李舒淇',18) index('吴亦凡') #相当于 inner('吴亦凡') 欢迎18岁李舒淇登录日记页面 测试本函数的执行效率:0.5007114410400391 欢迎吴亦凡登录博客园首页 测试本函数的执行效率:0.6006894111633301 Process finished with exit code 0
标准版的装饰器;
def wrapper(f):
def inner(*args,**kwargs): # 函数的定义:* 聚合 args = ('李舒淇',18)
'''添加额外的功能:执行被装饰函数之前的操作'''
ret = f(*args,**kwargs) #* 打散:f(*args) --> f(*('李舒淇',18)) --> f('李舒淇',18)
''''添加额外的功能:执行被装饰函数之后的操作'''
return ret
return inner
3、装饰器的执行过程(步骤详解)
- 图片详解:
- 文字详解:
1.第一步执行@wrapper装饰器,相当于执行 func=wrapper(func);
2.第二步把被装饰函数的函数名当做参数,带入到装饰器参数,即f=func,执行装饰器;
3.第三步返回 inner ,即wrapper(fun)的结果是得到 inner 即func=inner ;
4.第三步执行func(),等同于执行inner(),所以会执行装饰器的的内嵌函数,先执行print('此处代码执行在被装饰函数调用之前'),然后执行被装饰函数func(),执行print('in func'),在执行print('此处代码执行在被装饰函数调用之后'),并且把被装饰函数的执行结果(print('in func'))返回给执行者func()
- 具体代码:
def wrapper(f):
def inner(*args,**kwargs):
print('此处代码执行在被装饰函数调用之前')
ret=f(*args,**kwargs)
print('此处代码执行在被装饰函数调用之后')
return ret
return inner
@wrapper #相当于 func=wrapper(fun)
def func():
print('in func')
func()
此处代码执行在被装饰函数调用之前
in func
此处代码执行在被装饰函数调用之后
Process finished with exit code 0
4、python 中多个装饰器的执行顺序:
- 装饰器函数在被装饰函数定义好后立即执行。多个装饰器的调用顺序是自下往上的。
- 被装饰函数执行时,装饰器的执行顺序是从上往下的。
def wrapper1(f1):
print('in wrapper1')
def inner1(*args,**kwargs):
print('in inner1')
ret = f1(*args,**kwargs)
return ret
return inner1
def wrapper2(f2):
print('in wrapper2')
def inner2(*args,**kwargs):
print('in inner2')
ret = f2(*args,**kwargs)
return ret
return inner2
def wrapper3(f3):
print('in wrapper3')
def inner3(*args,**kwargs):
print('in inner3')
ret = f3(*args,**kwargs)
return ret
return inner3
@wrapper1
@wrapper2
@wrapper3
def func():
print('in func')
func()
# in wrapper3
# in wrapper2
# in wrapper1
# in inner1
# in inner2
# in inner3
# in func
#装饰器函数在被装饰函数定义好后立即执行。多个装饰器的调用顺序是自下往上的。
# 被装饰函数执行时,装饰器的执行顺序是从上往下的。
分析:
分析:
func = wrapper3(func) ---> 先打印'in wrapper3', func = inner3 ,f3 = func
func = wrapper2(func) --->即 inner3 = wrapper2(inner3) ---> 先打印'in wrapper2', inner3 = inner2 ,f2 = inner3 --> func = inner2
func = wrapper1(func) --->即 inner2 = wrapper1(inner2) --->先打印'in wrapper1', inner2 = inner1 ,f1 = inner2 --> func = inner1
执行 func() 即执行执行 inner1() ,先打印 'in inner1',再执行 f1(),即执行inner2()
即执行inner2() ,先打印 'in inner2',再执行 f2(),即执行inner3()
即执行inner3() ,先打印 'in inner3',再执行 f3(),即执行func(),打印 'in func '
5、装饰器的应用
# 装饰器的应用:登录认证
# 这周的周末作业:模拟博客园登录的作业。装饰器的认证功能。
- 基本框架
def login():
pass
def register():
pass
status_dict={
'username':None,
'status':False
}
def auth(f):
'''
你的装饰器完成:访问被装饰函数之前,写一个三次登录认证的功能。
登录成功:让其访问被装饰得函数,登录没有成功,不让访问。
:param f:
:return:
'''
def inner(*args,**kwargs):
'''访问函数之前的操作,功能'''
ret = f(*args,**kwargs)
'''访问函数之后的操作,功能'''
return ret
return inner
def article():
print('欢迎访问文章页面')
def comment():
print('欢迎访问评论页面')
def dariy():
print('欢迎访问日记页面')
article()
comment()
dariy()
def login():
dic = {}
username = input('请输入用户名').strip()
password = input('请输入密码').strip()
if username in register() and password == register()[username]:
dic[username] = password
print('登录成功')
else:
print('用户名或者密码错误')
return dic
def register():
dic_1 = {}
with open('a',encoding='utf-8') as f:
for line in f:
a,b = line.strip().split()
dic_1[a] = b
return dic_1
status_dict = {'username':None,'status':False}
def auth(f):
def inner(*args,**kwargs):
if status_dict['status']:
ret = f(*args,**kwargs)
return ret
else:
status_dict['username'] = login()
status_dict['status'] = True
ret = f(*args, **kwargs)
return ret
return inner
出处:https://www.cnblogs.com/wushaofan/p/17156647.html
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
关于JS定时器的整理
JS中使用Promise.all控制所有的异步请求都完
js中字符串的方法
import-local执行流程与node模块路径解析流程
检测数据类型的四种方法
js中数组的方法,32种方法
前端操作方法
数据类型
window.localStorage.setItem 和 localStorage.setIte
如何完美解决前端数字计算精度丢失与数