装饰器
知识储备
- 定义函数未被调用,函数内部不执行
- 函数名代指整个函数
例1:
def f1():
print("123")
def f1():
print("456")
f1()
#输出
456
例2:
def f2():
print("123")
def f3(xxx):
xxx()
f3(f2)
#输出
123
装饰器流程分析:
写代码要遵循开放封闭原则,虽然在这个原则适用于面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现功能的代码不允许被修改,但是可以被扩展,即:
- 封闭:已实现的功能代码块
- 开放:对扩展开发
def outer(func):
def inner():
print("log")
return func()
return inner
@outer
def f1():
print("F1")
def outer(func):...
# @ + 函数名
# 功能:
# 1.自动执行outer函数并且将其下面的函数名f1当作参数传递
# 2.将outer函数的返回值重新赋值给f1
@outer
def f1():
print("F1")
传递参数:
例1、传递一个参数:
# s1.py #
def outer(func):
def inner(a):
print("before")
r = func(a)
print("after")
return r
return inner
@outer
def f1(arg):
print(arg)
return "fuck you"
# s2.py #
import s1
ret = s2.f1('fafafa')
print("return",ret)
# 输出
before
fafafa
after
return fuck you
例2、传递多个参数
传递多个参数通过*args和**kwargs
def outer(func):
def inner(*args,**kwargs):
print("before")
r = func(*args,**kwargs)
print("after")
return r
return inner
@outer
def f1(arg):
print(arg)
return "fuck you"
多层装饰器:
一个函数可以被多个装饰器装饰,用户从最外层开始逐层调用,返回值则是从最里层逐层向外返回。
下面这个例子就是通过多层装饰器来实现用户登录和权限验证:
USER_INFO = {}
def check_login(func):
def inner(*args, **kwargs):
if USER_INFO.get("is_login",None):
ret = func(*args, **kwargs)
return ret
else:
print("请登录")
return inner
def check_admin(func):
def inner(*args, **kwargs):
if USER_INFO.get('user_type',None) == 2:
ret = func(*args, **kwargs)
return ret
else:
print("无权查看")
return inner
@check_login
@check_admin
def index():
"""
管理员用户
:return:
"""
print("index")
@check_login
def home():
"""
普通用户的登录
:return:
"""
print("home")
def login():
user = input("请输入用户名:")
if user == "admin":
USER_INFO['is_login'] = True
USER_INFO['user_type'] = 2
else:
USER_INFO['is_login'] = True
USER_INFO['user_type'] = 1
def main():
while True:
inp = input("1.登录;2.查看信息;3.超级管理员管理 \n >>>")
if inp == "1":
login()
elif inp == "2":
home()
elif inp == "3":
index()
main()
带参数的装饰器:
还有更牛逼的装饰器吗?我们来看下面的例子
#!/usr/bin/env python
#coding:utf-8
def Before(request,kargs):
print 'before'
def After(request,kargs):
print 'after'
def Filter(before_func,after_func):
def outer(main_func):
def wrapper(request,kargs):
before_result = before_func(request,kargs)
if(before_result != None):
return before_result;
main_result = main_func(request,kargs)
if(main_result != None):
return main_result;
after_result = after_func(request,kargs)
if(after_result != None):
return after_result;
return wrapper
return outer
@Filter(Before, After)
def Index(request,kargs):
print 'index'
functools.wraps
上述的装饰器虽然已经完成了其应有的功能,即:装饰器内的函数代指了原函数,注意其只是代指而非相等,原函数的元信息没有被赋值到装饰器内部。例如:函数的注释信息
def outer(func):
def inner(*args, **kwargs):
print(inner.__doc__) # None
return func()
return inner
@outer
def function():
"""
asdfasd
:return:
"""
print('func')
如果使用@functools.wraps装饰装饰器内的函数,那么就会代指元信息和函数。
def outer(func):
@functools.wraps(func)
def inner(*args, **kwargs):
print(inner.__doc__) # None
return func()
return inner
@outer
def function():
"""
asdfasd
:return:
"""
print('func')