Python 装饰器与函数调用机制(复习笔记 · 2026-07-07)

一、最基础:def 是定义,() 是调用

  • def say_hello(): print("Hello!") ------ 只定义,不执行。函数体被"存起来",不打印任何东西。
  • say_hello() ------ 有括号 = 调用 = 真正执行,才会打印 "Hello!"。
  • 如果删掉调用那行,程序什么都不输出(函数只定义、从没被喊去跑)。

❗ 误区:以为 @装饰器 会自动让函数运行。不会,必须显式写 名字() 才执行。

二、无参装饰器:名字被重新贴到 wrapper 上

复制代码
def my_decorator(func):
    def wrapper():
        print("函数执行前")
        func()
        print("函数执行后")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

执行流程

  1. def my_decorator:定义装饰器函数(不跑)。

  2. def say_hello:定义原函数(不跑)。

  3. @my_decorator 等价于 say_hello = my_decorator(say_hello)

    • 调用 my_decorator,传入原函数;
    • 内部定义 wrapper(不跑),return wrapper 把 wrapper 交出去;
    • say_hello 这个名字现在指向 wrapper(不再是原函数)。
  4. say_hello() 实际执行 wrapper()

    函数执行前
    Hello!
    函数执行后

关键结论

  • @装饰器 本质 = 函数名 = 装饰器(函数名),把名字重新绑定到新函数。
  • 装饰器执行时(@那行)只定义和返回,不打印;打印发生在你后续调用时。
  • 没有调用那行 → 什么都不输出。

三、Python 的"指向"不是 C 指针(重要纠偏)

❗ 当时类比错了的地方,已全部纠正:

|----------------------|-------------------------------------------------------|
| 原错误类比 | 正确概念 |
| 方法是内存块,指针从上往下扫到哪执行到哪 | def 语句本身执行了(创建函数对象),但函数体不执行,只是存起来等调用 |
| 指向像 C 指针,知道内存哪块就跳去执行 | Python 名字是引用/reference (标签贴对象),不是 C 指针,不能指针运算 |
| 占多少内存要关心 | 函数对象很小(几百字节),Python 有自动 GC,学习阶段不用管内存 |
| Python 有指针 | 没有指针;有调用栈、有 list(动态数组)、有 numpy.ndarray(AI 必用) |

Java 学习者对照表(学过 Java,基本能直接迁移)

|---------------------------|-------------------------------|
| Java 认知 | Python 对应 |
| 方法定义不运行,要 obj.method() 才调 | ✅ 一样,def 不跑,func() 才跑 |
| 对象靠引用、有 GC、有调用栈/堆 | ✅ Python 一样,且一切皆对象(连函数都是) |
| primitive 在栈、对象在堆 | Python 更统一:全是对象、全靠引用 |
| 无裸指针、不能指针运算 | ✅ Python 也没有 |
| 要 new 才创建对象 | Python 不用 new,赋值即创建 |
| 要手动 free/delete | Python 自动 GC,不用管 |

唯一要"忘掉"的:C 的手动内存管理 + 指针算术。Python 比 Java 还省心。

四、(*args, **kwargs):装饰器的"万能接口"

复制代码
def wrapper(*args, **kwargs):
    result = original_function(*args, **kwargs)
    return result
  • 调用 target_function()(空括号)→ args=() 空元组、kwargs={} 空字典,啥都没接
  • target_function(1, 2, name="小澪")args=(1,2)kwargs={'name':'小澪'}

|------------|-------------|----------|
| 写法 | 接住 | 存为 |
| *args | 位置参数(按顺序的值) | 元组 tuple |
| **kwargs | 关键字参数(名字=值) | 字典 dict |

  • 定义处的 * / ** = 收集(打包收到的参数)。
  • 调用处的 original_function(*args, **kwargs)* / ** = 解包(摊开传回去)。
  • 作用:让装饰器通用,不管被装饰函数要不要参数都能透传。无参函数传空进去正好。

❗ 误区:以为 (*args, **kwargs) 是"必须填两个"。不是,是"能接住任意参数"的兜底,不传就都是空的。

五、带参装饰器(装饰器工厂)= 多一层

复制代码
def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def say_hello():
    print("Hello!")

say_hello()

三层接参(最关键,别混)

|-------|----------------------------|-----------------|---------------|
| | 函数 | 接住 | 来自 |
| 1 | repeat(num_times) | 配置参数 3 | repeat(3) |
| 2 | decorator(func) | 被装饰函数 say_hello | @ 语法 |
| 3 | wrapper(*args, **kwargs) | 调用时参数 | say_hello() |

❗ 当时误解:@repeat(3) 把 say_hello 传给了 repeat。错!

  • repeat(3) 先算 → 传 num_times=3 → 返回 decorator(内部记住 num_times=3)。
  • 然后 @decorator 才把 say_hello 传给 decoratorfunc
  • 不是同一个函数接的两个东西,是先吃配置、再吐出一个定制装饰器去接函数。

对比无参装饰器

|------------------|-------------------------------------------|
| 无参 @df | 带参 @repeat(3) |
| df 直接接原函数 | repeat 先接 3 → 吐 decorator;decorator 再接原函数 |
| 两层(df / wrapper) | 三层(repeat / decorator / wrapper) |

多出的 repeat 层唯一作用:接收配置参数,返回真正能装饰函数的 decorator → 所以叫"装饰器工厂"。

六、for _ in range(n):循环 n 次

  • range(3) 产生 0, 1, 2(从 0 到 n-1,共 n 个)。
  • for _ in range(n): = "循环 n 次",每轮执行缩进块。
  • _ 是占位变量名,表示"这个数我不用",纯占位(写 for i in ... 也一样,只是 i 没被用)。
  • 带参装饰器打印三次,就是 for _ in range(num_times)num_times=3 决定的;改成 5 就打印 5 次。
  • range() 不是列表,是惰性序列,省内存,学习阶段只需知道"range(n) = 0 到 n-1 共 n 个数"。

七、今日核心心法(背下来)

  1. def 造函数不跑,名字() 才跑。
  1. @装饰器 = 函数名 = 装饰器(函数名),名字被重新指向新函数。
  1. 没写调用 → 不输出;要输出必须显式 名字()
  1. 名字是引用不是指针,内存 Python 自动管。
  1. (*args, **kwargs) 是装饰器万能接口,定义处收集、调用处解包。
  1. 带参装饰器多一层"工厂":先收配置、再产装饰器、最后接函数。
  1. range(n) + for = 循环 n 次;_ 是占位变量。
相关推荐
zh路西法10 分钟前
【双目相机 深度估计】PixelXYZ 3D 双目相机标定与实时深度估计全流程
python·opencv·相机标定·深度估计·双目相机·sgbm
雨落在了我的手上21 分钟前
Java数据结构(九):栈和队列
java·开发语言·数据结构
卷无止境21 分钟前
Python 相对导入与绝对导入的坑:从原理到工程实践
后端·python
FriendshipT25 分钟前
Ultralytics:简要解读YOLOv8 → YOLO11 → YOLO26网络架构
人工智能·pytorch·python·深度学习·yolo·目标检测
BaoshengTT26 分钟前
成都理想贴膜能否分期及汽车贴膜分期行业规则 保圣威固 7V 不凡门店
python·汽车
卷无止境28 分钟前
Python调试那点事儿:从pdb到日志系统的实战指南
后端·python
j7~28 分钟前
【C语言】《C语言自定义类型(结构体+联合体+枚举类型)》--详解
c语言·开发语言·深度学习·结构体·位段·联合体·枚举类型
Escalating_xu39 分钟前
C++11 彻底吃透 emplace_back 与 push_back(最全闭环:左右值|深浅拷贝|移动构造|万能引用|完美转发)
开发语言·c++
正和视觉教育43 分钟前
深圳CCD视觉培训:快速掌握机器视觉检测核心技术
人工智能·python·计算机视觉·视觉检测
axinawang44 分钟前
第16课:编码、解码、转义字符、转义序列、输出格式化
python