Python装饰器理解和固定格式

Python装饰器理解和固定格式

闭包

闭包函数,可以简单一句话概括,即内层函数引用外层函数的变量,并且进行调用执行,即该内层函数就是是一个闭包函数。
举例子:

def outside():
    a = "哈哈!"
    def inside():  # 当前inside函数即为一个闭包函数
        print(a)
    return inside

装饰器

装饰器,简单理解就是程序代码在运行中,在函数前面动态增加的功能方式。
举例子:
假设当前我们计算1-1000万相加。

def test_sum():
    sum_result = 0
    for i in range(10000001):
        sum_result += i
    return sum_result

print(test_sum())

假设我想计算这个函数执行多久,则可以另外在定义一个计算时间的函数。

import time

def timer(func):
    start_time = time.time()
    func()
    t = time.time() - start_time
    print(f"当前函数执行时间是:{t}")
   
"""执行函数"""
timer(test_sum)

上述计时函数,如果在大量函数都需要计时的情况时,会有很多重复使用timer()调用。
此时我们可以使用python的装饰器概念,来实现简易操作。
代码如下:

import time

def timer(func):
    def inner():
        start_time = time.time()
        result = func()
        t = time.time() - start_time
        print(f"当前函数执行时间是:{t}")
        return result
    return inner

"""这里用@加上定义的装饰器名称,即可以给函数动态加上装饰器内部定义的功能"""
@timer
def test_sum():
    sum_result = 0
    for i in range(1000001):
        sum_result += i
    return sum_result

print(test_sum())

执行结果:

当前函数执行时间是:0.06981754302978516
500000500000

Process finished with exit code 0

上述代码中有些缺陷,假设我的被装饰函数testsum以及其他被装饰函数需要入参时,且这些入参都不固定,则我们的装饰器中的inner函数需要重新优化一下。

import time

def timer(func):
    """此处,我们将内层函数的入参写成随意入参,则可以装饰不固定入参的函数"""
    def inner(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        t = time.time() - start_time
        print(f"当前函数执行时间是:{t}")
        return result
    return inner

@timer
def test_sum():
    sum_result = 0
    for i in range(1000001):
        sum_result += i
    return sum_result

print(test_sum())

总结,我们可以直接记住装饰器的固定格式,因为这个装饰器的格式基本通用。

def 装饰器的名字(func):
    def inner(*args, **kwargs):
        """此处是被装饰函数执行前需要的操作代码"""
        result = func(*args, **kwargs)
        """此处是被装饰函数执行后需要的操作代码"""
        return result
    return inner

此时有个新的需要,假设我们的装饰器也需要入参时,则我们的装饰器2层嵌套需要变成3层嵌套使用了。
一般网上教程装饰器函数名称喜欢用decorator和wrapper。
举例,我们在计时完一个函数之后,需要再等待可以自定义的几秒。

import time

def timer(sleep_time):
    def decorator(func):
        def inner(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            t = time.time() - start_time
            print(f"当前函数执行时间是:{t}")
            time.sleep(sleep_time)
            return result
        return inner
    return decorator

@timer(sleep_time=10)
def test_sum():
    sum_result = 0
    for i in range(1000001):
        sum_result += i
    return sum_result

print(test_sum())

执行结果如下:

当前函数执行时间是:0.05884051322937012
500000500000

Process finished with exit code 0

我们看到在函数执行时间结果之后和计算结果出之前,停顿了10s。

此时我们引入一个新问题。
我们可以通过__name__属性来获取函数的名称。

def test_sum():
    sum_result = 0
    for i in range(1000001):
        sum_result += i
    return sum_result

print(test_sum.__name__)

执行结果为:test_sum
但是如果加上装饰器,就会变了。

import time

def timer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        t = time.time() - start_time
        print(f"当前函数执行时间是:{t}")
        return result
    return inner

@timer
def test_sum():
    sum_result = 0
    for i in range(1000001):
        sum_result += i
    return sum_result

print(test_sum.__name__)

执行结果是:inner
函数执行的__name__属性变成装饰器的内部函数行,如果有需要依赖的name属性时,就会导致错误。
此时我们可以用一个已经写好的装饰器,代码优化成如下:

import time
from functools import wraps

def timer(func):
    """此时会把name属性也改成需要被装饰的函数名称"""
    @wraps(func)
    def inner(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        t = time.time() - start_time
        print(f"当前函数执行时间是:{t}")
        return result
    return inner

@timer
def test_sum():
    sum_result = 0
    for i in range(1000001):
        sum_result += i
    return sum_result

print(test_sum.__name__)

综上所述,装饰器的标准格式代码成如下:

import time
from functools import wraps

def timer(sleeptime):
    def decorator(func):
        @wraps(func)
        def inner(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            t = time.time() - start_time
            print(f"当前函数执行时间是:{t}")
            time.sleep(sleeptime)
            return result
        return inner
    return decorator


@timer(sleeptime=10)
def test_sum():
    sum_result = 0
    for i in range(1000001):
        sum_result += i
    return sum_result

print(test_sum())
print(test_sum.__name__)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值