装饰器
知识储备
- 定义函数未被调用,函数内部不执行
- 函数名代指整个函数
例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.超级管理员管理 >>>") 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')