装饰器

一、开放封闭原则

开放封闭原则:在不修改源代码与原函数的调用方式的情况下,为函数添加新功能, 对修改封闭,对扩展开放

二、什么是装饰器

装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

三、装饰器的基本框架

# @outer语法来调用outer,规定传入被装饰的函数对象,所以参数固定为一个,接受被装饰的函数对象
from functools import wraps
def outer(func):  
    @wraps(func)  # 系统的wraps带参装饰器:改变inner的假指向,本质外界使用的还是inner,但是打印显示的是wraps中的函数 
    # 不能确定被装饰的函数的参数:来者不拒,用可边长来接受
    def inner(*args, **kwargs):
        print('执行被装饰函数之前 你可以执行的操作')
        res = func(*args, **kwargs)  # 解压带给原功能
        print('执行被装饰函数之后 你可以执行的操作')
        return res
    return inner 
# 使用装饰器(outer),得到新功能(inner)
# 用被装饰的函数名去接受装饰器的执行结果,调用装饰器时传入被装饰的函数对象
@outer  # fn = outer(fn) = inner
def fn(): 
    pass
# 表面感觉调用的是原函数,本质调用的是闭包(inner),使用fn调用和fn定义及inner需要参数统一
fn()

四、装饰器的使用

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper

@timmer
def foo():
    time.sleep(3)
    print('from foo')
foo()

五、带参装饰器

# 通常,装饰器为被装饰的函数添加新功能,需要外界的参数
# uter参数固定一个,就是func
# inner参数固定同被装饰的函数,也不能添加新参数
# 可以借助函数的嵌套定义,外层给内层传参
def wrap(info):
    def outer(func):
        # info = 0
        def inner(*args, **kwargs):
            print('新:拓展的新功能,可能也需要外界的参数%s' % info)
            res = func(*args, **kwargs)
            return res
        return inner
    return outer

@wrap('外部参数') #fn = wrap(info):  fn = inner函数的内存地址
def fn(): pass

六、叠加多个装饰器

def outer(func):
    def inner(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    return inner


def check_user(func):
    def inner(*args, **kwargs):
        # 账号的验证功能
        user = args[0]  # type: str
        if not (user.isalpha() and len(user) >= 3):
            print('账号不合法')
            return False

        res = func(*args, **kwargs)
        return res
    return inner

def check_pwd(func):
    def inner(*args, **kwargs):
        pwd = args[1]
        if len(pwd) < 3:
            print('密码不合法')
            return False

        res = func(*args, **kwargs)
        return res
    return inner

def format_return(func):
    def inner(*args, **kwargs):
        res = func(*args, **kwargs)
        if res:
            return '登录成功'
        return '登录失败'
    return inner


# 登录的原功能

@format_return
@check_user
@check_pwd
def login(user, pwd):
    if user == 'owen' and pwd == '123':
        return True
    return False

user = input('user: ')
pwd = input('pwd: ')
res = login(user, pwd)
print(res)

# 执行过程:调用login => 进入第一个装饰器(format_return)的inner => 进入第二个装饰器(check_user)的inner => 进入第三个装饰器(check_pwd)的inner => 开始返回,从第三个返回到第二个再返回到第一个,最后返回到外界调用的位置

七、登录认证装饰器

def login_auth(func):
    from core import src
    def inner(*args, **kwargs):
        if src.user_info['name']:
            print('已登录!')
            res = func(*args, **kwargs)
            return res
        else:
            src.login()
    return inner

八、装饰器类 

import time


class A:
    func = None

    # 原本的功能
    def __init__(self, func):
        """
        实例化对象 调用
        :param func:
        """
        self.func = func

    # 扩展功能
    def __call__(self, *args, **kwargs):
        """
        实例化对象() 调用
        :param args:
        :param kwargs:
        :return:
        """
        _start = time.time()
        res = self.func(*args, **kwargs)
        _end = time.time()
        print("函数调用时间: ", _end - _start)
        return res


@A
def add(a, b):
    time.sleep(1)
    return a + b


print(add(1, 3))

 

posted on 2020-05-15 23:19  软饭攻城狮  阅读(136)  评论(0编辑  收藏  举报

导航