python 装饰器

@根据一些python装饰器例子,了解装饰器的原理和工作机制

装饰器:所谓函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行合理的扩充。本质是函数闭包的语法糖
函数闭包:一个函数,其参数和返回值都是函数
语法糖:指计算机语言中添加的某种语法,这种语法对语言的功能没有影响

  1. 语法糖没有增加新功能,只是一种更方便的写法
  2. 语法糖可以完全等价地转换为原本非语法糖的代码

装饰器的装饰函数时候的特点

  1. 在第一次调用之前增强
  2. 只增强一次

实例代码如下:

  1. 装饰器问题引入y
import time
"""
函数逻辑(查找奇数)和辅助功能(记录时间)耦合在一起了.
- 缺点: 不方便修改,容易引起bug
> 能不能将辅助功能从主要功能函数中抽离出来?
"""

def print_odds():
    """
    输出0~100之间所有奇数,并统计函数执行时间
    """
    start_time = time.clock()   # 起始时间
    # 查找并输出所有奇数
    for i in range(100):
        if i % 2 == 1:
            print(i)
    end_time = time.clock()     # 结束时间
    print("it takes {} s to find all the olds".format(end_time - start_time))

if __name__ == '__main__':
    print_odds()
  1. 直接分离两个函数
import time

"""
将辅助功能(记录时间)抽离成一个辅助函数count_time,在辅助函数count_time中调用主要功能函数print_odds.
- 优点: 解耦,函数职责分离.
- 缺点: 要通过辅助函数来调用主要功能函数,不方便.
> 我们的目标: 能不能在调用主要功能函数时自动完成对时间的统计?
"""
def count_time(func):
    """
    统计某个函数的运行时间
    """
    start_time = time.clock()  # 起始时间
    func()  # 执行函数
    end_time = time.clock()  # 结束时间
    print("it takes {} s to find all the olds".format(end_time - start_time))

def print_odds():
    """
    输出0~100之间所有奇数,并统计函数执行时间
    """
    for i in range(100):
        if i % 2 == 1:
            print(i)
            
if __name__ == '__main__':
    # print_odds()
    count_time(print_odds)
   
  1. 通过闭包增强主要功能函数
import time
"""
通过闭包增强主要功能函数print_odds,给它增加一个统计时间功能
缺点: 需要显式进行闭包增强
"""


def print_odds():
    """
    输出0~100之间所有奇数,并统计函数执行时间
    """
    for i in range(100):
        if i % 2 == 1:
            print(i)


# 闭包本质上是一个函数
# 闭包函数的传入参数和返回值也都是函数
# 闭包函数的返回值函数是对传入函数进行增强后的结果
def count_time_wrapper(func):
    """
    闭包,用于增强函数func: 给函数func增加统计时间的功能
    """

    def improved_func():
        start_time = time.clock()   # 起始时间
        func()                      # 执行函数
        end_time = time.clock()     # 结束时间
        print("it takes {} s to find all the olds".format(end_time - start_time))

    return improved_func


if __name__ == '__main__':
    # 调用count_time_wrapper增强函数
    print_odds = count_time_wrapper(print_odds)
    print_odds()# improved

  1. 通过装饰器去增强函数
import time

"""
通过装饰器进行函数增强,只是一种语法糖,本质上跟上个程序完全一致.
"""

def count_time_wrapper(func):
    """
    闭包,用于增强函数func: 给函数func增加统计时间的功能
    """

    def improved_func():
        start_time = time.clock()  # 起始时间
        func()  # 执行函数
        end_time = time.clock()  # 结束时间
        print(
            "it takes {} s to find all the olds".format(end_time - start_time))

    return improved_func

@count_time_wrapper
def print_odds():
    """
    输出0~100之间所有奇数,并统计函数执行时间
    """
    for i in range(100):
        if i % 2 == 1:
            print(i)

if __name__ == '__main__':
    # 装饰器等价于在第一次调用函数时执行以下语句:
    # print_odds = count_time_wrapper(print_odds)
    print_odds()
  1. 增强含有返回值的函数
import time


def count_time_wrapper(func):
    """
    闭包,用于增强函数func: 给函数func增加统计时间的功能
    """

    def improved_func():
        start_time = time.clock()   # 起始时间
        func()                      # 执行函数
        end_time = time.clock()     # 结束时间
        print("it takes {} s to find all the olds".format(end_time - start_time))


    return improved_func


def count_odds(lim=100):
    """
    输出0~lim之间所有奇数,并统计函数执行时间
    """
    cnt = 0
    for i in range(lim):
        if i % 2 == 1:
            cnt+=1
    return cnt


# 对于含有返回值的函数,调用闭包增强后,不能成功返回,但是成功增强了辅助功能
# 对于含有参数的函数,调用闭包增强后,不能成功接收参数
# if __name__ == '__main__':
#     print('增强前')
#     print(count_odds())         # 装饰前函数能正常返回,能接收参数
#     print('----------------------')
#     print('增强后')
#     count_odds = count_time_wrapper(count_odds)
#     print(count_odds())         # 装饰后函数不能正常返回,不能接收参数

if __name__ == '__main__':
    print('增强前')
    print(count_odds(lim=10000))         # 装饰前函数能正常返回,能接收参数
    print('----------------------')
    print('增强后')
    count_odds = count_time_wrapper(count_odds)
    print(count_odds(lim=10000))         # 装饰后函数不能正常返回,不能接收参数
  1. 增强含有返回值的函数2
import time


def count_time_wrapper(func):
    """
    闭包,用于增强函数func: 给函数func增加统计时间的功能
    """

    def improved_func(*args, **kwargs):     # 增强函数应该把就饿收到的所有参数传给原函数
        start_time = time.clock()   # 起始时间
        ret = func(*args, **kwargs)                     # 执行函数
        end_time = time.clock()     # 结束时间
        print("it takes {} s to find all the olds".format(end_time - start_time))
        return ret      # 增强函数的返回值应该是原函数的返回值

    return improved_func


def count_odds(lim=100):
    """
    输出0~100之间所有奇数,并统计函数执行时间
    """
    cnt = 0
    for i in range(lim):
        if i % 2 == 1:
            cnt += 1
    return cnt


if __name__ == '__main__':
    print(count_odds(lim=100000))  # 装饰前函数能正常返回,能接收参数
    print('-----------')
    count_odds = count_time_wrapper(count_odds)
    print(count_odds(lim=100000))  # 装饰后函数能正常返回,能接收参数
  1. 增强带有返回值函数的模板写法
def general_wrapper(func):

    def improved_func(*args, **kwargs):    # 接收函数参数
        # 增强功能
        ret = func(*args, **kwargs)        # 传入参数并记录返回值
        # 增强功能
        return ret                         # 返回未增强函数的返回值

    return improved_func
  1. 多个装饰器
import time


def count_time_wrapper(func):
    """
    闭包,用于增强函数func: 给函数func增加统计时间的功能
    """

    def improved_func():
        start_time = time.clock()  # 起始时间
        func()  # 执行函数
        end_time = time.clock()  # 结束时间
        print("it takes {} s to find all the olds".format(end_time - start_time))

    return improved_func


def log_wrapper(func):
    """
    闭包,用于增强函数func: 给func增加日志功能
    """

    def improved_func():
        start_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))  # 起始时间
        func()  # 执行函数
        end_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))  # 结束时间
        print("Logging: func:{} runs from {} to {}".format(func.__name__, start_time, end_time))

    return improved_func


@count_time_wrapper
@log_wrapper
def count_odds():
    """
    输出0~100之间所有奇数,并统计函数执行时间
    """
    cnt = 0
    for i in range(100):
        if i % 2 == 1:
            cnt += 1
    return cnt


if __name__ == '__main__':
    count_odds()
   
  1. 多个装饰器执行顺序 按装饰的顺序执行
def wrapper1(func1):
    print('set func1')  # 在wrapper1装饰函数时输出

    def improved_func1():
        print('call func1')  # 在wrapper1装饰过的函数被调用时输出
        func1()

    return improved_func1


def wrapper2(func2):
    print('set func2')  # 在wrapper2装饰函数时被输出

    def improved_func2():
        print('call func2')  # 在wrapper2装饰过的函数被调用时输出
        func2()

    return improved_func2


# @wrapper1
# @wrapper2
def original_func():
    pass


if __name__ == '__main__':
    # original_func = wrapper1(wrapper2(original_func))

    # print(original_func.__name__)               # original_func = original_func()
    original_func = wrapper2(original_func)
    # print(original_func.__name__)               # original_func = improved_func2(封装original_func)()
    original_func = wrapper1(original_func)
    # print(original_func.__name__)               # original_func = improved_func1(封装improved_func2(封装original_func)())()

    original_func()
    print('-----')
    original_func()
 
  1. 多个装饰器执行的逻辑
def wrapper1(func1):
    print('set func1')

    def improved_func1():
        print('call func1')
        func1()     # 封装了improve_func2(original_func)

    return improved_func1


def wrapper2(func2):
    print('set func2')

    def improved_func2():
        print('call func2')
        func2()     # 封装了original_func

    return improved_func2


# @wrapper1
# @wrapper2
def original_func():
    pass


if __name__ == '__main__':
    # original_func = wrapper1(wrapper2(original_func))

    original_func = wrapper2(original_func)
    print(original_func.__name__)
    original_func = wrapper1(original_func)
    print(original_func.__name__)
    # original_func封装了improved_func1(improve_func2(original_func))


    original_func()
    print('-----')
    original_func()

11.增强函数也带有参数值

import time

def log_wrapper(info='Everything works'):
    def internal_log_wrapper(func):
        def improved_func():
            start_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))  # 起始时间
            func()  # 执行函数
            end_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))  # 结束时间
            print("Logging: func:{} runs from {} to {}, info:[{}]".format(func.__name__, start_time, end_time, info))

        return improved_func
    return internal_log_wrapper


@log_wrapper(info='informmmmmmmm')
def count_odds():
    """
    输出0~100之间所有奇数,并统计函数执行时间
    """
    cnt = 0
    for i in range(100):
        if i % 2 == 1:
            cnt += 1
    return cnt

if __name__ == '__main__':
    count_odds()

备注:本文中实例代码来源于B站公开资源,源视频链接为:[传送门](https://www.bilibili.com/video/BV1SZ4y1s7cv)
如需删除,请联系本人qq:975485055

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值