Python函数之—— 装饰器(Day13)
一.什么是装饰器
顾名思义,装饰器指为其他函数添加新功能
装饰器定义:本质就是函数,功能是为其他函数添加新功能
二.装饰器需要遵循的原则
1.不修改被装饰函数的源代码(开放封闭原则)
2.为被装饰函数添加新功能后,不修改被修改函数的调用方式
3.装饰器的本质 :闭包函数
功能:就是在不改变原函数调用方式的情况下,在这个函数前后加上扩展功能
示例1:
import time
def timmer(func):
#函数名可以当做函数的参数
def inner():
start = time.time()
func()
end = time.time()
print(end - start)
return inner def hahaha():
time.sleep(0.1)
print('aaaa')
示例2:
def timmer(func): #---> hahaha
def inner(x,y):
func(x,y) # --->hahaha
return inner def hahaha(a,b):
time.sleep(0.1)
print(a,b) def kkk(a):
print(a)
三.装饰器的主要功能和装饰器的固定结构
装饰器的主要功能:
在不改变函数调用方式的基础上在函数的前、后添加功能。
装饰器的固定格式:
def timer(func):
def inner(*args,**kwargs):
'''执行函数之前要做的'''
re = func(*args,**kwargs)
'''执行函数之后要做的'''
return re
return inner
语法糖
import time
def wrapper(func): # 装饰
def inner(*args, **kwargs):
start = time.time()
ret = func(*args, **kwargs)
end = time.time()
print(end - start)
return ret
return inner @wrapper
def lll():
time.sleep(0.1)
print('hello') lll()
四.
1.带参数的装饰器
def outer(flag):
def timer(func):
def inner(*args,**kwargs):
if flag:
print('''执行函数之前要做的''')
re = func(*args,**kwargs)
if flag:
print('''执行函数之后要做的''')
return re
return inner
return timer @outer(False)
def func():
print(111) func()
F = False
def outer(flag):
def wrapper(func):
def inner(*args,**kwargs):
if flag:
print('before')
ret = func(*args,**kwargs)
print('after')
else:
ret = func(*args, **kwargs)
return ret
return inner
return wrapper @outer(F) #-->@wrapper -->hahaha = wrapper(hahaha) #-->hahaha == inner
def hahaha():
print('hahaha') @outer(F) #shuangww = outer(shuangww)
def shuangww():
print('shuangwaiwai') shuangww()
hahaha()
2.多个装饰器装饰同一个函数
def qqxing(func): #func = pipixia_inner
def qqxing_inner(*args,**kwargs):
print('in qqxing:before')
ret = func(*args,**kwargs) #pipixia_inner
print('in qqxing:after')
return ret
return qqxing_inner def pipixia(func): #dapangxie
def pipixia_inner(*args,**kwargs):
print('in pipixia:before')
ret = func(*args,**kwargs) #dapangxie
print('in pipixia:after')
return ret
return pipixia_inner #qqxing(pipixia_inner) -->dapangxie = qqxing_inner()
@qqxing #dapangxie = qqxing(dapangxie) -->dapangxie = qqxing(pipixia(dapangxie)) -->
@pipixia #dapangxie = pipixia(dapangxie)
def dapangxie():
print("饿了么")
dapangxie()
3.开放封闭原则
(1)对扩展是开放的
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
(2)对修改是封闭的
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
练习:
'''
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),
要求登录成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,
可以用eval('{"name":"egon","password":"123"}')转成字典格式
'''
# user_dict = {
# 'pang':'123456',
# 'panda':'binbin',
# 'nezha':'101010'
# }
# print(type(user_dic))
auth_status = {
'user':None, #设置全局的字典
'status':False
}
def auth(func):
def inner(*args,**kwargs):
if auth_status['status']: #如果auth_status为真,直接调用就行
ret = func(*args, **kwargs) # index/home
return ret
else:
username = input('username : ').strip()#.strip()避免用户输入带有空格的用户名
password = input('password : ').strip()
# 读文件获取用户信息
f = open('conf') #文件句柄
user_info = f.read() #读取user用户信息
user_dic = eval(user_info) #通过eval转换成字典
if user_dic.get(username) and user_dic[username] == password:#获取字典的k,确认有存在的用户名并找到对应的密码
print('login successful')
auth_status['user'] = username
auth_status['status'] = True
ret = func(*args,**kwargs) #index/home 如果登录成功执行func
return ret
else:
print('login failed')
return inner @auth #装饰器
def index():
print("欢迎来到首页") @auth
def home():
print("欢迎回家") index()
index()
home()
index()
# #认证功能
# #获取用户名和密码
# username = input('username : ').strip()
# password = input('password : ').strip()
# #读文件获取用户信息
# f = open('conf')
# user_info = f.read()
# user_dic = eval(user_info)
# if user_dic.get(username) and user_dic[username] == password:
# print('login successful')
# else:
# print('login failed')
'''
进阶练习:
1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
2.编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),
就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
'''
url_l = []
from urllib.request import urlopen def get_cache(func):
def inner(*args,**kwargs):
url = args[0]
filename = str(hash(url))
if url in url_l:
f = open(filename,'rb')
ret = f.read()
else:
url_l.append(url)
ret = func(*args, **kwargs)
f = open(filename,'wb')
f.write(ret)
f.close()
return ret
return inner @get_cache
def get(url):
return urlopen(url).read() print(get('http://www.cnblogs.com/linhaifeng'))
Python函数之—— 装饰器(Day13)的更多相关文章
- Python函数06/装饰器
Python函数06/装饰器 目录 Python函数06/装饰器 内容大纲 1.装饰器 1.1 开放封闭原则 1.2 装饰器 2.今日练习 内容大纲 1.装饰器 1.装饰器 1.1 开放封闭原则 扩展 ...
- python——函数之装饰器
1 问题 实际生活中,我们很难一次性就把一个函数代码写得完美无缺.当我们需要对以前的函数添加新功能时,我们应该怎么做? 2 问题解决思路 (1)可以直接修改原来的函数,在函数内直接修改.当我们对多个函 ...
- python函数、装饰器、迭代器、生成器
目录: 函数补充进阶 函数对象 函数的嵌套 名称空间与作用域 闭包函数 函数之装饰器 函数之迭代器 函数之生成器 内置函数 一.函数补充进阶 1.函数对象: 函数是第一类对象,即函数可以当作数据传递 ...
- Python 函数之装饰器
1.函数 #### 第一波 #### def foo(): print 'foo' foo #表示是函数 foo() #表示执行foo函数 #### 第二波 #### def foo(): print ...
- python函数闭包-装饰器-03
可调用对象 callable() # 可调用的(这个东西加括号可以执行特定的功能,类和函数) 可调用对象即 callable(对象) 返回为 True 的对象 x = 1 print(cal ...
- Python函数的装饰器修复技术(@wraps)
@wraps 函数的装饰器修复技术,可使被装饰的函数在增加了新功能的前提下,不改变原函数名称,还继续使用原函数的注释内容: 方便了上下文环境中不去更改原来使用的函数地方的函数名: 使用方法: from ...
- Python函数的装饰器修复技术(@wraps)
@wraps 函数的装饰器修复技术,可使被装饰的函数在增加了新功能的前提下,不改变原函数名称,还继续使用原函数的注释内容: 方便了上下文环境中不去更改原来使用的函数地方的函数名: 使用方法 from ...
- Python函数加工厂-装饰器
引言: 函数和装饰器好比程序界的加工厂: 1.函数一般可用来加工一种或者多种数据类型的数据:字符串.数字.列表.字典等 举一个简单例子:已知半径求面积 def s(r): s = 3.14 * r * ...
- Python函数的装饰器
函数的装饰器. 1. 装饰器 开闭原则: 对功能的扩展开放 对代码的修改是封闭 通用装饰器语法: def wrapper(fn): def inner(*args, **kwargs): # 聚合 & ...
随机推荐
- websocket echo test
http://www.websocket.org/echo.html .net websocket server http://superwebsocket.codeplex.com/ http:// ...
- 淡入淡出效果模板 js
html文件中: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> &l ...
- python-获取本机mac地址
#!/usr/bin/env python #-*- coding:utf-8 -*- ############################ #File Name: getmac.py #Auth ...
- C语言指针解说
指针是C语言的一种数据类型.类似于C中的其它类型,比如int ,char 等.既然指针是一种类型,当我们定义该类型变量.该类型变量就称为指针变量. C中有了指针就有了指向. 指向:指针变量指向本身保存 ...
- Ocelot + IdentityServer4 坑自己
现像是 connect/userinfo 可以访问 但是api都提示401 后面发现是在appsettings.json "Options": {"Authority&q ...
- https原理与实践
HTTPS 原理与证书实践 分类: Web应用 1.1 网络安全知识 1.1.1 网结安全出现背景 网络就是实现不同主机之间的通讯,网络出现之初利用TCP/IP协议簇的相关协议概念,已经满足了 ...
- Asteroids - poj 3041(二分图最大匹配问题)
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 17258 Accepted: 9386 Description Be ...
- 【spring boot】在spring boot下使用多线程
使用场景: 方法处理到某一步,需要将信息交给另一个线程去处理!! =================================================================== ...
- 我的第7个java程序--把java web项目改为java project项目--mybatis
连接数据库需要 程序,连接字符串,查询语句 主程序->读取连接字符串->读取查询语句->把查询到的值赋值给映射对象->打印对象属性 java project的好处,不用做那么多 ...
- HTML <td> 标签的 width 属性
<table border="1" width="100%"> <tr> <th>Month</th> < ...