欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python装饰器理解和固定格式

程序员文章站 2022-06-22 08:32:22
Python装饰器理解和固定格式闭包装饰器闭包闭包函数,可以简单一句话概括,即内层函数引用外层函数的变量,并且进行调用执行,即该内层函数就是是一个闭包函数。举例子:def outside(): a = "哈哈!" def inside(): # 当前inside函数即为一个闭包函数 print(a) return inside装饰器装饰器,简单理解就是程序代码在运行中,在函数前面动态增加的功能方式。举例子:假设当前我们计算1-1000万相加。de...

Python装饰器理解和固定格式

闭包

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

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

装饰器

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

def test_sum():
    sum_result = 0
    for i in range(10000000):
        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(1000000):
        sum_result += i
    return sum_result

print(test_sum())

执行结果:

当前函数执行时间是:0.0937497615814209
499999500000

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(1000000):
        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(1000000):
        sum_result += i
    return sum_result

print(test_sum())

执行结果如下:

当前函数执行时间是:0.08781886100769043
499999500000

Process finished with exit code 0

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

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

def test_sum():
    sum_result = 0
    for i in range(1000000):
        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(1000000):
        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(1000000):
        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(1000000):
        sum_result += i
    return sum_result

print(test_sum())
print(test_sum.__name__)

本文地址:https://blog.csdn.net/weixin_43046974/article/details/107254532