Python 闭包和装饰器

闭包

简介
  • 在函数内部再定义一个函数,内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包
  • 优点:闭包似优化了变量,原来需要类对象完成的工作,闭包也可以完成
  • 缺点:由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存
  • nonlocal访问外部函数的局部变量
def outer_func(number):
    def inner_func(inner_number):
        return number + inner_number

    return inner_func


# 给外部函数复制,20传递给number,并返回内部函数
fun = outer_func(20)

print(fun(100))  # 120
print(fun(200))  # 220

装饰器

简介
  • 装饰器本质上就是一个函数(或类),能够在不修改现有函数代码的情况下,对现有函数的功能实现扩充。
  • 装饰器其实就是一个闭包,把一个函数当做返回参数。
  • 装饰器:
    • 装饰器为函数
      • 被装饰对象为函数
        • 无参装饰器
        • 带参装饰器
      • 被装饰对象为类
    • 装饰器为类
      • 被装饰对象为函数
      • 被装饰对象为类
普通方式
def fun(test):
    def inner():
        print('inner')
        test()

    return inner


def fun1():
    print('func1')


def fun2():
    print('func2')


fun_test = fun(fun1)
fun_test()
fun_test = fun(fun2)
fun_test()

输出信息:

inner
func1
inner
func2

函数装饰器

无参装饰器
  • @符号是 python 装饰器的语法,在定义函数的时候使用,避免再一次赋值操作
  • @outer func等价于 outer(func)
  • 执行 func 函数实际上是执行 inner 函数的内容
def decorator(func):
    def inner():
        print('开始处理数据')
        func()
        print('数据处理完毕')

    return inner


@decorator
def func():
    print('正在处理数据')


func()

输出信息:

开始处理数据
正在处理数据
数据处理完毕
带参装饰器:被装饰对象带参
def decorator(func):
    def inner(x, y):
        print('开始处理数据')
        result = func(x, y)
        print('数据处理完毕')
        return result

    return inner


@decorator
def func(a, b):
    print('正在处理数据')
    return a * b


result = func(2, 3)
print(result)

输出信息:

开始处理数据
正在处理数据
数据处理完毕
6
带参装饰器:被装饰对象不定长参数
def decorator(func):
    def inner(*args, **kwargs):
        print("开始处理数据")
        result = func(*args, **kwargs)
        print("数据处理完毕")
        return result

    return inner


@decorator
def func1(a, b):
    print('正在处理...')
    return "%s-%s" % (a, b)


@decorator
def func2(a, b, c):
    print('正在处理...')
    return "%s,%s,%s" % (a, b, c)


result1 = func2('A', 'B', 'C')
print('返回数据:', result1)

result2 = func1("a", "b")
print('返回数据:', result2)

输出信息:

开始处理数据
正在处理...
数据处理完毕
返回数据: A,B,C
开始处理数据
正在处理...
数据处理完毕
返回数据: a-b
带参装饰器:装饰器带参
def decorator(arg):  # 装饰器参数
    def middle(func):
        def inner(x, y):
            print("开始数据处理")
            x *= arg
            y *= arg
            result = func(x, y)
            print("数据处理完毕")
            return result

        return inner

    return middle


@decorator(10)
def func(a, b):
    print('正在处理数据...')
    return a * b


result = func(3, 4)
print(result)

输出信息:

开始数据处理
正在处理数据...
数据处理完毕
1200

类装饰器

  • __init__初始化操作
  • __call__装饰器调用时操作
class Decorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print('开始处理数据')
        self.func()
        print('数据处理完毕')


@Decorator
def fun():
    print('数据处理中。。。')


fun()

输出信息:

开始处理数据
数据处理中。。。
数据处理完毕

functools.wraps()

  • 使用装饰器时,有一些细节需要被注意。例如,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变)。
  • 添加后由于函数名和函数的doc发生了改变,对测试结果有一些影响

例如:

def decorator(func):
    def inner():
        """
        inner函数
        :return:
        """
        pass

    return inner


@decorator
def func():
    """
    被装饰函数
    :return:
    """
    pass


print(func.__name__)
print(func.__doc__)

输出信息:

inner

        inner函数
        :return:

由此可见,被装饰的func的函数信息丢失了,解决这个问题可以使用functools.wraps()函数

import functools


def decorator(func):
    # func的属性绑定
    @functools.wraps(func)
    def inner():
        """
        inner函数
        :return:
        """
        pass

    return inner


@decorator
def func():
    """
    被装饰函数
    :return:
    """
    pass


print(func.__name__)
print(func.__doc__)

输出信息:

func

    被装饰函数
    :return:

未完待续。。。

猜你喜欢

转载自blog.csdn.net/qq_14876133/article/details/81211986