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): # 聚合 & ...
随机推荐
- 设计模式之迪米特原则(LoD)
迪米特原则也叫作最少知识原则,也就是:一个对象应该对其他对象有最少的了解.也就是说一个对象应该尽量的保证高内聚性,不应该对外有太多的public方法.
- Matlab中使用Java api画图图形并保存为jpeg格式
直接上代码: close all; import java.io.*; import java.awt.*; import java.awt.image.BufferedImage; import j ...
- Python学习之格式符
%s 字符串 (采用str()的显示) %r 字符串 (采用repr()的显示) %c 单个字符 %b 二进制整数 %d 十进制整数 %i 十进制整数 %o ...
- Hash索引和BTREE索引2
索引是数据库中用来提高性能的最常用工具.所有MySql列类型都可以被索引.索引用于快速找出在某个列中有一特定值的行.如果不使用索引,MYSQL必须从第一条记录开始然后读完整个表直到找出相关的行.常用的 ...
- python 循环结构
for循环 list或tuple可以表示一个有序集合.如果我们想依次访问一个list中的每一个元素呢?比如 list: L = ['Adam', 'Lisa', 'Bart'] print L[0] ...
- iOS 学习笔记六 【APP中的文字和APP名字的国际化多语言处理】
今天为新手解决下APP中的文字和APP名字的国际化多语言处理, 不多说了,直接上步骤: 1.打开你的项目,单机project名字,选中project,直接看图吧: 2.创建Localizable.st ...
- C# 子类实例化过程
刚研究了一下C#子类实例化的过程. 首先我遇到了如下一个问题: 有类A,里面写了一个有参的构造函数,并没有提供默认的无参构造函数.现在类B继承了类A,没有写任何的构造函数. 这时如果想实例化类B就会产 ...
- go的sync.Map
sync.Map这个数据结构是线程安全的(基本类型Map结构体在并发读写时会panic严重错误),它填补了Map线程不安全的缺陷,不过最好只在需要的情况下使用.它一般用于并发模型中对同一类map结构体 ...
- ps -ef | grep java 查看所有关于java的进程
ps -ef | grep java 查看所有关于java的进程
- 【BZOJ2870】最长道路tree 点分治+树状数组
[BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来 ...