python装饰器

python之装饰器

1 什么是闭包?

1.1 变量解析规则

变量名加载顺序: 内置 => 全局 => 局部

变量名搜索顺序:局部 => 全局 => 内置

1.2 闭包函数的定义

函数内部定义的函数称为内部函数,该内部函数包含对外部(上层)作用域,而不是对全局作用域名字的,并且外层函数返回了内层函数的引用,那么该内部函数称为闭包函数

嵌套的函数,外部函数返回的是内部函数的引用,而内部函数可以使用外部函数的作用域,那么内部函数就称为闭包函数

  • 闭包函数属性:

    • 闭包函数是内部函数
    • 包含对外部作用域而非全局作用域的引用
    def outer(num1):
        # 在函数内部定义的函数,这个函数使用了外部函数的变量
        # 那么这个内层函数就是闭包
        def inner(num2):
            return num1 + num2
    
        return inner
    
    
    # 调用外层函数,传参;返回内部函数,传进的参数不会被释放
    inner = outer(100)
    print(inner(200))
    

用于闭包引用了外部函数中的变量,会导致没有及时释放变量,会消耗内存空间

1.3 闭包的优缺点

优点:闭包优化了变量,原来需要类对象完成的工作,闭包也可以完成

缺点:由于闭包函数引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

1.4 通用闭包

# 通用闭包
def set_func(func):
    def call_func(*args, **kwargs):
        print("要增加的功能代码")
        return func(*args, **kwargs)  # 作为实参传入时,需要拆包
    return call_func # 返回内层函数的引用

@set_func # 等价于 test = set_func(test)
def test():
    print("为这个函数增加功能")

  

2 什么是装饰器?

装饰器本质上就是一个函数或类,能够在不修改现有函数代码的情况下,对现有函数的功能实现扩充。

装饰器其实可以是一个闭包,把一个函数当做返回参数,装饰器本质是调用外部的函数返回了是闭包(内部函数);也可以是一个类

装饰器:

  • 装饰器为函数

     被装饰对象为函数:无参装饰器、带参装饰器

  • 被装饰对象为类

      装饰器为类:被装饰对象为函数、被装饰对象为类

2.1 装饰器的使用过程

1、调用了装饰器对应的外层函数,并且将被装饰函数作为实参传递给外层函数。目的是为了能够让内层函数使用这个作为外层函数的局部变量的被装饰函数,从而执行被装饰函数的代码实现。

2、外层函数将内层函数的引用返回给被装饰函数的原函数名(变量名),实现闭包

2.2 装饰器的原则

对函数或者方式实现功能扩充,但不能修改原有的功能

  • 不能修改被装饰的函数的源代码

  • 不能修改被装饰的函数的调用方式

2.3 装饰器的作用-开放封闭

在不修改被装饰对象源代码以及调用方式的前提下为其添加新功能。

装饰器的作用就是为已经存在的函数或对象添加额外的功能,使用装饰器能够使用原函数名调用实现除了原来功能之外的扩展功能。

2.4 带参装饰器

def set_param(param: int):
    def set_func(func):
        def call_func(*args, **kwargs):
            if param == 1:
                print('1')
            elif param == 2:
                print(2)
            else:
                print('其他')
            return func(*args, **kwargs)

        return call_func

    return set_func


@set_param(1)
def test():
    print('测试函数')


test()

@set_param(1) 这个是带参装饰器
执行过程如下:
@set_param(1)装饰器装饰的函数 等价于 test = set_param(1)(test)

  1. 先执行set_param(1),将参数1传进到函数中去,并返回函数set_func

  2. 然后执行set_func(test), 将被装饰的函数传入到装饰器内层的函数中去, 并返回call_func的引用给test

2.5 装饰器实现路由功能

# 存储请求路径和对应的函数
url_func_dt = {}


def router(url: str):
    def set_func(func):
        url_func_dt[url] = func

        def call_func(*args, **kwargs):
            return func(*args, **kwargs)

        return call_func

    return set_func


@router('/index.html')
def index():
    with open('./index.html') as f:
        content = f.read()
    return content


def application(env, start_header):
    file_name = env['path_info']
    start_header('200 0k', [('Content-type', 'text/html;charset=utf-8')])
    url_func_dt[file_name]()

什么是路由?根据浏览器的请求找到相应的函数去执行任务。

2.6 类装饰器

class Decorator:
    def __init__(self, func):
        self._func = func

    def __call__(self, *args, **kwargs):
        print('类装饰器')
        return self._func(*args, **kwargs)


@Decorator
def test():
    print('被装饰函数')


test()

@Decorator 类装饰器 等价于 test = Decorator(test)

posted @ 2022-07-28 10:03  三叶草body  阅读(131)  评论(0)    收藏  举报