Python装饰器

装饰器

知识储备

  • 定义函数未被调用,函数内部不执行
  • 函数名代指整个函数

例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')

  

posted @ 2017-01-16 16:19  Bourbon.Tian  阅读(234)  评论(0编辑  收藏  举报