Python函数系统学习路线第205讲_核心原理与实战案例详解【教程】

12次阅读

Python函数系统学习路线第205讲_核心原理与实战案例详解【教程】

Python 函数不是语法糖,是第一类对象——这意味着你传它、存它、动态造它、替它,都合法。不理解这点,学再多装饰器、闭包、functools.partial 都是空中楼阁。

Python 函数是第一类对象,def 和 lambda 均创建 function 实例,区别在于 lambda 仅支持表达式;闭包由自由变量捕获决定;@wraps 确保装饰器保留原函数元信息。

Python 函数系统学习路线第 205 讲_核心原理与实战案例详解【教程】

Python 函数不是语法糖,是第一类对象——这意味着你传它、存它、动态造它、替它,都合法。不理解这点,学再多装饰器、闭包、functools.partial 都是空中楼阁。

为什么 def 定义的函数能被赋值给变量?

因为 def 实际上在执行时创建了一个 function 类型的实例,并绑定到名字上。名字只是引用,不是函数本身。

  • def f(): return 42 等价于 f = lambda: 42(底层都是 function 对象)
  • g = f 不会复制函数逻辑,只是新增一个指向同一对象的引用
  • id(f) == id(g) 在未重新赋值前为 True
  • 修改 f.__defaults__ 会影响所有同引用函数(注意:可变默认参数陷阱根源在此)

lambdadef 的本质 区别 在哪?

不在“是否匿名”,而在“是否允许语句”。lambda 只能包含表达式,不能有 returnif 块、赋值语句;def 编译为含完整代码对象(__code__)的可调用对象。

  • lambda x: x if x > 0 else 0 ✅ 合法(三元表达式)
  • lambda x: return x ❌ 语法错误(return 是语句)
  • def 函数有 __name____doc____annotations__ 等完整属性;lambda__name__ 恒为 ''
  • 性能差异微乎其微,别为“快一点”硬套 lambda——可读性优先

闭包的判定标准不是“嵌套定义”,而是“自由变量捕获”

判断一个内层函数是不是闭包,看它是否引用了外层函数 作用域 中 ** 非全局 ** 且 ** 未作为参数传入 ** 的变量——这种变量叫自由变量(free variable),会被打包进 __closure__ 元组。

立即学习Python 免费学习笔记(深入)”;

def make_adder(n):     def add(x):         return x + n  # ← n 是自由变量     return add 

add5 = make_adder(5) print(add5.closure) # print(add5.closure[0].cell_contents) # 5

  • 若内层函数没引用外层局部变量(比如只用 global 变量),__closure__None
  • nonlocal 声明不改变闭包结构,只允许赋值;真正构成闭包的是“读取”动作
  • 常见坑:循环中创建多个闭包却共享同一个变量(如 for i in range(3): funcs.append(lambda: i))→ 全部返回 2,需用默认参数固化:lambda i=i: i

functools.wraps 解决的不是“看起来像原函数”,而是“行为一致”

装饰器本质是替换原函数对象。不加 @wraps(func),新函数会丢失原函数的 __name____doc____module____annotations__ 等元信息,导致 help() 失效、调试器跳转错位、类型检查 工具 误报。

from functools import wraps 

def my_timer(func): @wraps(func) # ← 关键!否则 func.name 变成 'wrapper' def wrapper(*args, *kwargs): import time start = time.time() result = func(args, **kwargs) print(f'{func.name} took {time.time() - start:.2f}s') return result return wrapper

  • @wraps 本质是把 func__dict__ 中的元属性拷贝到 wrapper
  • 若装饰器本身带参数(如 @retry(max_tries=3)),@wraps 要放在最内层函数上,不是装饰器工厂函数上
  • 不依赖 functools 也能手动同步:用 wrapper.__name__ = func.__name__ 等,但易漏项

自由变量怎么查、code.co_freevars 怎么对应 closure、装饰器嵌套时 @wraps 放哪一层——这些细节不跑一遍 dir() 和打印对象,光看教程永远模糊。

星耀云
版权声明:本站原创文章,由 星耀云 2025-12-27发表,共计1706字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources