一. 概念
这两天在学装饰器,概念简单说一下
装饰器:
- 定义:是一个函数,用来装饰另一个函数,给其附加新的功能
- 特点:1.不修改被装饰函数 2.不修改被装饰函数的调用方式 3.不修改被装饰函数的返回值
- 实现:高阶函数 + 嵌套函数
1.函数(名)即'变量'
2.高阶函数:
- 把一个函数名当做实参传个另一个函数
- 返回值包含函数名
3.嵌套函数
二. 几个小demo
1.给login增加一个运行时间的功能,首先把login这个函数名当做参数传给test1,此时可以把函数名'login'看做一个整体(函数体)保存在内存中,它的地址是 0x00000294C6CED0D0,当test1函数在调用func时,会运行这一段代码,我们来看装饰器的定义:test1 是一个函数√ ,给login增加了新功能(run time) √
对照装饰器的特点:1.不修改被装饰函数(login)的代码 √ 2.不修改被装饰函数的调用方式×,我们现在调用的是test1()函数 3.不修改被装饰函数的返回值 ? 这里login暂时没有返回值...
显然这不是一个装饰器
(PS:如果在生产环境中,修改了这个调用方式,麻溜收拾东西滚蛋.)
__author__ = 'tjt'
# 给登录模块增加一个程序运行时间的功能
import time
# 运行时间
def test1(func):
print(func) # <function login at 0x00000294C6CED0D0>
start_time = time.time()
func()
stop_time = time.time()
print("run time is ", stop_time-start_time)
# 登录模块
def login():
print("logging...")
time.sleep(3)
print("success")
test1(login)
-------结果---------
<function login at 0x00000294C6CED0D0>
logging...
success
run time is 3.0100364685058594
2.再来看第2个demo
此时,没有修改被装饰函数login代码,(貌似)也没有修改它的调用方式,是不是就可以认为test1就是一个装饰器了呢?显然,还不行,因为你需要用同名函数来接收test1的返回值,
__author__ = 'tjt'
# 给登录模块增加一个程序运行时间的功能
import time
# 运行时间
def test1(func):
def wrapper(): # 加一层函数
# print(func) # <function login at 0x00000294C6CED0D0>
start_time = time.time()
func()
stop_time = time.time()
print("run time is ", stop_time-start_time)
return wrapper # 现在,我们给test1加一个返回值
# 登录模块
def login():
print("logging...")
time.sleep(3)
print("success")
# 我们用一个与login()函数的同名变量来接收test1()的返回值
login = test1(login)
# 此时login保存的是wrapper函数的函数体,即在内存中保存的地址
# 我们再调用login()这个方法
# 没修改login源代码,增加了新的功能,貌似也没有修改调用方式
login()
--------结果---------
logging...
success
run time is 3.0090436935424805
3.第3个demo
现在,有3个页面:index页面,home页面,blog页面
需求,进入index不需要登录,进入home和blog页面需要验证登录
(再增加一个登录状态的判断,就可以登录一次,后面只要判断状态就可以了,不必重复登录)
# author tjt
# 初始化一个用户
username, password = "tjt", "abc123"
# 这里又新嵌套了一层函数,此时参数变成了验证方式'func_type'
def test1(func_type):
# 之前传入的函数名'func'下移到这一层
def outer_wrapper(func):
def wrapper(*args, **kwargs):
# 登录输入
username1 = input("Username: ").strip()
password1 = input("Password: ").strip()
# 判定验证方式,本地文件验证
if func_type == "file":
# 验证
if username1 == username and password1 == password:
print("login success")
# res用来接收被装饰函数的返回值
res = func(*args, **kwargs)
return res # 返回这个值,不会更改被装饰函数的返回值
else:
exit("incorrect username or password")
elif func_type == "ldap": # 远端服务器验证
# 成功
return True
return wrapper
return outer_wrapper
def index():
print("welcome to index")
# 增加了参数,这里参数是验证方式
@test1(func_type="file")
def home():
print("in the home")
return "home page"
@test1(func_type="ldap")
def blog():
print("in the blog")
return "blog page"
index()
print(home())
print(blog())
三.总结
一开始也说过了,这里再唠叨一下,
装饰器贯穿1个思想,3个原则:
1个思想,函数(名)即'变量':把函数名当做变量传参到装饰器函数,实际上是把'函数体'所在的内存地址传进了装饰器函数
3个原则,1.不修改被装饰函数 2.不修改被装饰函数的调用方式 3.不修改被装饰函数的返回值
刚学习装饰器,讲得不对的地方欢迎指正,一起进步!