Python装饰器

import datetime
import time

count = 5

def loop():
    time1 = datetime.datetime.now()
    for i in range(count):
        time.sleep(1)
    time2 = datetime.datetime.now()
    print("循坏耗时:",(time2 - time1).seconds)

在loop方法中创建变量time1和time2,用来计算循环耗时,这种业务常用于性能测试,若是测试的方法很多,就会造成代码的冗余

可以在设计中使用装饰器来改善代码

核心思想:在一个现有的方法上扩展功能而不修改原来的代码

语法:在被扩展的方法上加“@装饰器名称”,python中的@也是AOP思想的一种实现

def log(func):
    def decorate(*args, **kw):
        print("被装饰的函数名称:", func.__name__)
        time1 = datetime.datetime.now()
        func(*args, **kw)
        time2 = datetime.datetime.now()
        print("循坏耗时:",(time2 - time1).seconds)
    return decorate

@log
def decorated():
    print("decorated函数被装饰后,函数名为:",decorated.__name__)
    for i in range(count):
        time.sleep(1)
decorated()

被装饰的函数名称: decorated
decorated函数被装饰后,函数名为: decorate
循坏耗时: 5

在高阶函数loop中继续创建decorate函数,用来封装被装饰的decorated方法,并在log函数代码块中返回。

log方法中的变量func指向了decorated方法,decorated方法被装饰后又指向了decorate方法。在调用decorated方法时,实际上调用了decorate,因此可以顺利完成性能检测。

装饰器是闭包的典型示例,即在返回的内部函数中引用了外部函数的变量。内部函数decorate中引用了log函数的参数func,并在log中返回了decorate对象,根据变量作用域规则,func参数是一个局部变量,在log方法执行完毕后内存空间应该被释放,不能在访问。然而在log中返回decorate对象时,decorate方法锁定了func变量,导致log执行完毕后,func参数的内存空间仍然存在,装饰器能正常执行。

小案例:计数器

def f1():
    ans = [0]

    def f2():
        ans[0] += 1
        return ans[0]
    return f2
count = f1()
for i in range(5):
    print("第%s次调用计数器,记录值为:%s" % (i, count()))

第0次调用计数器,记录值为:1
第1次调用计数器,记录值为:2
第2次调用计数器,记录值为:3
第3次调用计数器,记录值为:4
第4次调用计数器,记录值为:5

这里ans作为f1方法的局部变量,在f1的内部函数f2的作用下实现累加,每次循环调用都能记录上一次的值,局部变量ans的内存空间并没有随着f1的执行完毕而被销毁,因为在f1中返回f2对象时,f2方法就锁定了ans。即闭包的概念。

装饰器传递参数方法

方法一:在log外层继续定义一个函数,通过外层函数给装饰器传递参数

import datetime
import time
count = 5
def log_comment(content):
    def log(func):
        def decorate(*args, **kw):
            print("被装饰的函数名称:%s,当前业务是:%s" % (func.__name__, content))
            time1 = datetime.datetime.now()
            func(*args, **kw)
            time2 = datetime.datetime.now()
            print("循坏耗时:",(time2 - time1).seconds)
        return decorate
    return log

@log_comment("测试循环耗时")
def decorated():
    print("decorated函数被装饰后,函数名为:",decorated.__name__)
    for i in range(count):
        time.sleep(1)
decorated()

被装饰的函数名称:decorated,当前业务是:测试循环耗时
decorated函数被装饰后,函数名为: decorate
循坏耗时: 5

方法二:使用functools.warps内建方法,该方法专门用于创建修饰器

import datetime
import time
import functools

count = 5

def log(func, content):
    @functools.wraps(func)
    def decorate(*args, **kw):
        print("被装饰的函数名称:%s,当前业务是:%s" % (func.__name__, content))
        time1 = datetime.datetime.now()
        func(*args, **kw)
        time2 = datetime.datetime.now()
        print("循坏耗时:",(time2 - time1).seconds)
    return decorate

def decorated():
    print("decorated函数被装饰后,函数名为:",decorated.__name__)
    for i in range(count):
        time.sleep(1)

log(decorated, "这是装饰器参数")()

被装饰的函数名称:decorated,当前业务是:这是装饰器参数
decorated函数被装饰后,函数名为: decorated
循坏耗时: 5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值