关于装饰器

装饰器:

* 装饰器:本质是一个闭包
* 作用:核心思想:
在不改变被装饰对象内部代码和原有调用方式的基础之上在添加额外的功能

装饰器的简易版本:

给index函数添加统计执行时间的功能

def index():
    time.sleep(3)
index()


-----------------------------------------------------------------------------------------------------------------------
请注意:

  使用time函数时,要将time函数所在的模块导入,使用“import”。time函数表示的含义是:从当前时间到1970年1月1号0时0分1秒的时间间隔。
 因此,想要获得计时函数所用时间,需要得到未运行的时间间隔和已运行的时间间隔,之后两者相减,才是最终要用的结果。


import time


def index():
    time.sleep(3)
    print('from index')


def home():
    time.sleep(2)
    print('from home')


def func():
    time.sleep(2)
    print('from home')

# 1.先走这一步 # 3.调用outer函数
def outer(func):  # 以func以参数的形式传过来就写活了
    # func = index   这个写死了
    def get_time():   # 5.这个不会执行
        # func:index
        # 1. 在函数执行之前打一个时间点
        start_time = time.time()
        func()   # index
        # 2. 在函数执行完毕之后再打一个时间点
        end_time = time.time()

        # 3. 两个时间差就是函数实际执行时间
        print("函数执行了:%s秒" % (end_time - start_time))

    return get_time  # 6.返回get_time的内存地址

# 利用闭包的形式来传参
# res = outer(index)    # res:get_time
# res()   # res加括号实际就是get_time加括号

# 2.先走outer函数 # 4.把home传给func
home = outer(home)   # 7. home=get——time

home()   # home加括号实际就是get_time加括号


# 改变了原有的调用方式
# get_time(index)
# get_time(home)

解决参数的问题:

def index(name, username):
    time.sleep(3)
    print('from index')


def home(name):
    time.sleep(2)
    print('from home', name)


def outer(func):
    # func = index
    def get_time(*args, **kwargs):
        # func:index
        # 1. 在函数执行之前打一个时间点
        start_time = time.time()
        func(*args, **kwargs)  # index()  func('tony')
        # 2. 在函数执行完毕之后在打一个时间点
        end_time = time.time()

        # 3. 两个时间的差值就是函数的实际执行时间
        print("函数执行了:%s秒" % (end_time - start_time))

    return get_time

index = outer(index)
index('tony', username='tank')

---------------------------------------------------------------------------------------------------------------
补充以上运用到的:*args,**kwargs

*args

*是一种语法,args是一种约定俗称。如果定义一个函数时不知道使用者要用位置传参的方式传入多少个实参,可使用*args来进行接收所有多余的被传入的实参,这些多余的被传入实参会被打包成元组类型。

**kwargs
也是一种语法。kwargs则是后面形参名的约定俗称。如果定义一个函数时不知道使用者要用关键字传参的方式传入多少个实参,可使用kwargs来进行接收所有多余的被传入的实参,这些多余的被传入实参会被打包成字典类型。
---------------------------------------------------------------------------------------------------------------

解决返回值问题:

def home(name):
    time.sleep(2)
    print('from home', name)

def index():
    time.sleep(3)
    print('from index')
    return 'from index'

def outer(func):
    # func = index
    def get_time(*args, **kwargs):
        # func:index
        # 1. 在函数执行之前打一个时间点
        start_time = time.time()
        res=func(*args, **kwargs)  # index()  func('tony')
        # 2. 在函数执行完毕之后在打一个时间点
        end_time = time.time()

        # 3. 两个时间的差值就是函数的实际执行时间
        print("函数执行了:%s秒" % (end_time - start_time))
        return res
    return get_time
index = outer(index)
res=index()
print(res)

登录认证功能:

def home(name):
    print('from home')

def func():
    print('from func')
"""
    必须登录之后才能执行index函数
        如果不登录不让执行
"""
def login_auth(func):
    # func = index
    def auth(*args, **kwargs):
        # 写登录功能
        # 1.
        username = input('username:').strip()
        password = input('password:').strip()

        # 2. 验证用户名和密码是否正确
        if username == 'kevin' and password == '123':
            print('登录成功')
            res=func(*args, **kwargs)
            return res
        else:
            print('用户名或者密码错误')
    return auth

home=login_auth(home)
home('kevin')

装饰器固定格式:

def outer(func):
    def inner(*args, **kwargs):
        print('这个是函数执行之前可以添加的功能')
        res = func(*args, **kwargs)
        print('这个是函数执行之后可以添加的功能')
        return res

    return inner


def index():
    print('from index')


index = outer(index)
index()

装饰器的语法糖:

def outer(func):
    def inner(*args, **kwargs):
        print('这个是函数执行之前可以添加的功能')
        res = func(*args, **kwargs)
        print('这个是函数执行之后可以添加的功能')
        return res

    return inner


"""装饰器本质就是函数,函数就是功能"""
#语法糖
@outer  # index = outer(index)
def index():
    print('from index')

@outer  # home=outer(home)  -----------> home是outer函数的返回值(内部函数的函数名)
def home():
    print('from home')

home() # inner()
# index = outer(index)
index()

# home = outer(home)
# home()
"""
语法糖的书写规范:
    紧贴着被装饰对象的上方写
语法糖的内部原理:
    他会自定把被装饰对象的名字当成参数传给装饰器函数调用
"""
@outer  # func = outer(func)
def func():
    print('from func')
    
func()  # inner()

双层语法糖

def login_auth(func):
    # func = index
    def auth(*args, **kwargs):
        # 写登录功能
        # 1.
        username = input('username:').strip()
        password = input('password:').strip()

        # 2. 验证用户名和密码是否正确
        if username == 'kevin' and password == '123':
            print('登录成功')
            res = func(*args, **kwargs)
            return res
        else:
            print('用户名或者密码错误')

    return auth


def get_time(func):
    # func = index
    def inner(*args, **kwargs):
        # func:index
        # 1. 在函数执行之前打一个时间点
        start_time = time.time()
        res = func(*args, **kwargs)  # index()  func('tony')
        # 2. 在函数执行完毕之后在打一个时间点
        end_time = time.time()

        # 3. 两个时间的差值就是函数的实际执行时间
        print("函数执行了:%s秒" % (end_time - start_time))
        return res

    return inner


@login_auth  # index=login_auth(get_time内部的inner函数名)
@get_time  # get_time内部的inner函数名=get_time(index)
def index():
    time.sleep(2)
    print('from index')

index()  # auth()

多层语法糖练习题

# 判断七句print执行顺序
def outter1(func1):
    print('加载了outter1')
    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1

def outter2(func2):
    print('加载了outter2')
    def wrapper2(*args, **kwargs):
        print('执行了wrapper2')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2

def outter3(func3):
    print('加载了outter3')
    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')
        res3 = func3(*args, **kwargs)
        return res3
    return wrapper3


@outter1
@outter2
@outter3
def index():
    print('from index')

多认证登录功能

def login_auth(func):
    # func = index
    def auth(*args, **kwargs):
        # 判断用户是否登录了
        if is_login.get('is_login'):
            # 正常执行函数
            res = func(*args, **kwargs)
            return res
        # 写登录功能
        # 1.
        username = input('username:').strip()
        password = input('password:').strip()

        # 2. 验证用户名和密码是否正确
        if username == 'kevin' and password == '123':
            print('登录成功')
            res = func(*args, **kwargs)
            is_login['is_login'] = True
            return res
        else:
            print('用户名或者密码错误')

    return auth


@login_auth
def index():
    print('from index')


@login_auth
def home():
    print('from home')


index()
home()

装饰器的修复技术了解

from functools import wraps

def outer(func):
    # func = index
    @wraps(func)
    def get_time(*args, **kwargs):
        # func:index
        # 1. 在函数执行之前打一个时间点
        start_time = time.time()
        res = func(*args, **kwargs)  # index()  func('tony')
        # 2. 在函数执行完毕之后在打一个时间点
        end_time = time.time()

        # 3. 两个时间的差值就是函数的实际执行时间
        print("函数执行了:%s秒" % (end_time - start_time))
        return res

    return get_time

有参装饰器

# 有参装饰器就是带参数的装饰器
# 先前我们学习的装饰器就是无参装饰器:不到参数的装饰器

def outter(type):
    # type = 1
    def login_auth(func):
        # func = index
        def auth(*args, **kwargs):
            # 写登录功能
            # 1.
            username = input('username:').strip()
            password = input('password:').strip()

            # 2. 验证用户名和密码是否正确
            # with open('')
            """
                根据不同的参数用户名和密码来自于不同的位置
            """
            if type == 'file':
                print('用户名和密码来自于文件')
            elif type == 'mysql':
                print('用户名和密码来自于MySQL')
            elif type == 'oracle':
                print('用户名和密码来自于Oracle')

            # if username == 'kevin' and password == '123':
            #     print('登录成功')
            #     res = func(*args, **kwargs)
            #     return res
            # else:
            #     print('用户名或者密码错误')

        return auth
    return login_auth
# @login_auth  # 如果是index函数认证,用户名和密码来自于文件  login_auth(index, 1)
@outter('file') # @login_auth     # 如果是index函数认证,用户名和密码来自于文件  login_auth(index, 1)
def index():
    print('from index')

index()

# @login_auth  # 如果是home函数认证,用户名和密码来MySQL
@outter('mysql')  # 如果是home函数认证,用户名和密码来MySQL
def home():
    print('from home')

home()

@outter('oracle')  # 如果是func函数认证,用户名和密码来oracle
def func():
    print('from func')

func()

小练习

# 1.编写装饰器,实现函数返回值+100的功能。
def huang(func):
    def wrapper(*args, **kwargs):

        result = func(*args, **kwargs)
        return result + 100
    return wrapper


@huang
def test(num):
    return num


print(test(10))  # 输出110


# 2.通过一次调用使函数重复执行5次_装饰器

def five_times(func):

    def wrapper(*args, **kwargs):

        for i in range(5):
            func(*args, **kwargs)
    return wrapper


@five_times
def say_hello():
    print("Hello")


say_hello()



posted @ 2023-05-30 21:20  毓见  阅读(25)  评论(0)    收藏  举报