Python装饰器详解

本文详细介绍了Python装饰器,从基础准备如可调用对象、嵌套函数和描述器,到函数装饰器、类装饰器的实现和使用,以及装饰器在修饰协程中的应用。重点探讨了无参和有参装饰器,闭包,以及类装饰器在成员函数中的应用,帮助读者深入理解Python装饰器的工作原理和实战技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

装饰器

一、 基础准备

1、 可调用对象

在Python中,除了用户定义的函数,调用运算符(即 ())还可以应用到其他对象上。如果想判断对象能否调用,可以使用内置的 callable() 函数。Python 数据模型文档列出了以下 7 种可调用对象:

  1. 用户定义的函数

    使用def语句或lambda表达式创建

  2. 内置函数

    使用C语言(CPython)实现的函数,如:len()

  3. 内置方法

    使用C语言实现的方法,如:dict.get(key)

  4. 方法

    在类的定义体的函数

  5. 调用类是会运行类的__new__()方法创建一个实例,然后运行__init__()方法,初始化实例。最后把实例返回给调用方。因为Python没有new运算符,所以调用类相当于调用函数。(通常,调用类会创建那个类的实例,不过覆盖 __new__ 方法的话,也可能出现其他行为。)

  6. 类的实例

    如果类定义了__call__方法,那么它的实例可以作为函数调用

  7. 生成器函数

    使用yield关键字的函数或方法。调用生成器函数返回的是生成器对象

实例:把类的实例变成可调用对象

class Callable:
    def __call__(self, *args, **kwargs):
        return "类的实例对象被调用"


call = Callable()
print(call())
print(callable(call))

其相当于C语言里面的函数调用运算符的重载

2、 嵌套函数

嵌套函数是在另一个函数中定义的函数

使用场景:

  • 封装 - 数据隐藏
  • 贯彻 DRY原则
  • 闭包
2.1.1 封装

可以使用内层函数来保护它们不受函数外部变化的影响,也就是说把它们的作用域转换为局部作用域

def outer(n):
    count = 0  # 统计内层函数的调用次数

    def inner():
        print("内层函数被调用")
        nonlocal count
        count += 1  # 闭包处理

    return count

在全局作用域下,尝试去访问count变量会报错,访问内层函数也会报错

实例,递归函数的高级实现

def multi(n):
    if not isinstance(n, int):
        # 如果数字不是整型
        raise TypeError("n must be Integer")
    if n < 0:
        # 如果输入的数据小于0
        raise ValueError("n must be zero or positive")

    def inner_multi(n):
        # 内层函数嵌套求乘积
        if n <= 1:
            return 1
        return n * inner_multi(n - 1)

    return inner_multi(n)


print(multi(3))

当传入的数据不符合求乘积的规则时,报错

2.1.2 贯彻 DRY 原则

DRY 原则:

  • 是指在程序设计以及计算中避免重复代码,因为这样会降低灵活性、简洁性,并且有可能导致代码之间的矛盾
  • 其更多的是一种架构设计思想,在软件开发过程中的万事万物均可能重复,大到标准、框架、开发流程;中到组件、接口;小到功能、代码均纯存在自我重复。而 DRY 提倡的就是在软件开发过程中应消除所有这些自我重复

比如,函数装饰器的使用

2.1.3 闭包

闭包的介绍:

  • 在一个内部函数中,对外部作用域的变量进行引用,(并且一般外部函数的返回值为内部函数),那么内部函数就被认为是闭包

闭包的作用:

  1. 当闭包执行完后,仍然能够保持住当前的运行环境
  2. 闭包可以根据外部作用域的局部变量来得到不同的结果

Python装饰器的本质是返回一个函数地址,然后发生函数调用

比如

def print_():
    print("你好")
    def inner():
        print("hello")
    return inner  # 将内层函数的地址返回
def main(print_):
    # 将函数作为参数传输
    inner = print_()
    print(inner)  # 其为内层函数的地址
    inner()  # 调用内层函数
main(print_)

函数可以当做其他函数的参数进行传入,同时如果返回值是函数,则返回该函数的内存地址

3、 描述器

3.1 简介

描述器是一个Python对象,只要其具有__get__(), __set__(), __delete__()方法中任意一个方法的对象就叫做描述器。一个对象在访问描述器时,如果该属性是一个描述器,则默认属性回调规则会被__set__(), __get__(), __delete__()方法所覆盖

作用:

  • python内部自带的staticmethod, classmethod, property, super等都是描述器,在很多Python库中也都有描述器的身影,使用描述器能让你有更高的概率写出优美的代码、更简洁的API,并且会加深对Python理解
3.2 使用描述器
class Des:

    def 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码海探幽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值