一、Python 的底层视角:名字绑定(非常重要)

Python 中没有“变量”,只有“名字 → 对象”的绑定关系

你平时把 a 叫“变量”——在日常编程交流中没错;
但在 Python 的语言模型和解释器视角中,
更准确的说法是:a 是“名字(name)”,不是传统意义上的变量。

a = 10

含义是:
解释器创建一个值为 10 的 int 对象,并将该对象绑定到当前作用域中的名字 a

二、什么是装饰器(一句话定义)

装饰器就是:
在“定义阶段”,
接收一个对象(函数 / 类),
返回一个新对象,
并让原来的名字重新指向这个新对象。

三、装饰器语法只是语法糖(重点)

不管是函数还是类:

@decorator
obj

永远等价于:

obj = decorator(obj)

这是理解装饰器的一切基础,装饰器只是语法糖

四、装饰器什么时候执行?

装饰器在 定义阶段 执行
不是在函数调用 / 类实例化时执行

1. 什么叫“定义阶段”

函数的两个阶段

def foo():
    print("hello")
foo() # 调用阶段

这里有 两个完全不同的时间点:

  1. 定义阶段

    def foo():
        print("hello")
    

    Python 读取 def foo():
    创建一个函数对象
    把名字 foo 绑定到这个函数对象
    但 不执行函数体

    定义阶段就是指 Python 在执行模块顶层代码时,
    遇到 def 语句并创建函数对象的那个时刻。

  2. 调用阶段

    foo() # 调用阶段
    

    才会执行 print(“hello”)
    装饰器发生在 第 1 步:定义阶段

2. 例子

def my_decorator(func):
    print("装饰器执行了")   # 关键
    return func
@my_decorator
def hello():
    print("hello 函数执行")

如果没有装饰器@my_decorator,这两个函数只是创建了对象,不会执行内部代码,不会有任何输出
但是加了装饰器实际运行结果:

装饰器执行了

你还没有调用 hello()
但装饰器里的 print 已经执行了

  • 等价写法(理解核心)

    def my_decorator(func):
        print("装饰器执行了") 
        return func
    def hello():
        print("hello 函数执行")
    
    hello = my_decorator(hello) # 在函数对象定义完成后立即执行
    

    ① 创建 my_decorator 函数对象
    ② 创建 hello 函数对象
    ③ 调用 my_decorator(hello)
    ④ hello 重新绑定

更清晰的例子

def my_decorator(func):
    print("① 装饰器执行")
    
    def wrapper():
        print("③ wrapper 执行")
        func()
    
    return wrapper

@my_decorator
def hello():
    print("④ hello 执行")

print("② 定义结束")

hello()
  • 执行顺序结果

    ① 装饰器执行
    ② 定义结束
    ③ wrapper 执行
    ④ hello 执行

  • 执行顺序解析

    1 解释器读到 @my_decorator
    2 创建函数对象 hello
    3 执行 my_decorator(hello) (定义阶段)
    4 把返回的 wrapper 绑定给名字 hello
    5 程序继续往下执行
    6 调用 hello(),其实调用的是 wrapper()

五、函数装饰器(基础版)

示例

def my_decorator(func):
    def wrapper():
        print("前置逻辑")
        func()
        print("后置逻辑")
    return wrapper
    
@my_decorator
def hello():
    print("hello")

等价写法(名字绑定视角)

def my_decorator(func):
    def wrapper():
        print("前置逻辑")
        func()
        print("后置逻辑")
    return wrapper
   
hello = my_decorator(hello)

含义:

右边 hello:原函数对象
左边 hello:名字被重新绑定
新对象是 wrapper

六、带参数的装饰器(三层结构)

标准结构(一定记)

def case(param1, param2):
    def decorator(obj):
        # 装饰逻辑
        return obj
    return decorator

@case("01", "测试用例")
def func():
    pass

等价于

def case(param1, param2):
    def decorator(obj):
        # 装饰逻辑
        return obj
    return decorator

def func():
    pass

func = case("01", "测试用例")(func)

@case(…)
不是“只执行 case”,
而是语法强制要求:
先执行 case(…),再执行它的返回值(func)。

执行顺序

  1. 执行 case(“01”, “测试用例”)
  2. 返回 decorator
  3. 执行 decorator(func)
  4. 名字重新绑定

七、最基础的类装饰器

def class_decorator(cls):
    cls.tag = "测试类"
    return cls

@class_decorator
class MyClass:
    pass

等价写法

def class_decorator(cls):
    cls.tag = "测试类"
    return cls
MyClass = class_decorator(MyClass)
  • 右边的 MyClass

    是一个名字
    指向类对象
    作为参数传入装饰器

  • 左边的 MyClass

    是同一个名字
    被重新绑定
    指向装饰器返回的新对象

八、装饰器返回的对象,可能是哪几种?

  • 情况 1(最常见)

    def class_decorator(cls):
        cls.tag = "demo"
        return cls
    

    返回 原类对象
    名字仍然指向同一个类

  • 情况 2(换了一个新类)

    def class_decorator(cls):
        class NewClass(cls):
            pass
        return NewClass
    

    返回 全新的类对象
    MyClass 指向 NewClass

  • 情况 3(返回实例,不推荐)

    def class_decorator(cls):
        return cls()
    

    MyClass 不再是类
    而是实例对象

九、类装饰器的执行时间线

@class_decorator
class MyClass:
    pass

执行顺序:

  1. 执行 class 代码块
  2. 创建类对象
  3. 调用 class_decorator(MyClass)
  4. 名字 MyClass 重新绑定

十、带参数的类装饰器(结合你最初的 case)

def case(testcase_id, testcase_name):
    def decorator(cls):
        cls.testcase_id = testcase_id
        cls.testcase_name = testcase_name
        return cls
    return decorator

@case("01", "test")
class Template:
    pass

等价于:

def case(testcase_id, testcase_name):
    def decorator(cls):
        cls.testcase_id = testcase_id
        cls.testcase_name = testcase_name
        return cls
    return decorator
Template = case("01", "test")(Template)

十一、总结

装饰器就是:
在定义阶段,
把一个“名字指向的对象”传进去加工,
再让这个名字重新指向加工后的返回对象。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐