functools.partial 是 Python 中用于部分应用(冻结部分参数)的高阶函数,解决重复传固定参数和适配单参回调场景的问题;它通过预绑定位置或关键字参数生成新可调用对象,调用时自动合并参数,但冻结值在构造时确定且不可动态更新。

partial 是什么,它解决什么问题
functools.partial 不是魔法,它只是把一个函数和部分参数“冻结”成新函数。你遇到的典型场景是:某个函数总要传几个固定参数(比如 log_level="INFO"、timeout=30),每次调用都写一遍太啰嗦;或者你要把函数塞进 map、threading.Thread 这类只接受单参回调的地方,但原函数需要多参。
怎么正确创建和调用 partial 函数
核心就一行:from functools import partial,然后用 partial(func, *args, **kwargs) 构造。注意两点:
-
*args是位置参数,会从左到右“占位”,后续调用时再补剩下的位置参数 -
**kwargs是关键字参数,会覆盖后续调用时传入的同名参数(不是合并) - 被冻结的参数不能在后续调用中重复传,否则会报
TypeError: got multiple values for argument
示例:
from functools import partial
<p>def send_request(url, method="GET", timeout=10, headers=None):
return f"{method} {url} (timeout={timeout})"</p><h1>冻结 method 和 timeout</h1><p>get_with_5s = partial(send_request, method="GET", timeout=5)
print(get_with_5s("<a href="https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39">https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39</a>")) # GET <a href="https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39">https://www.php.cn/link/710ba53b0d353329706ee1bedf4b9b39</a> (timeout=5)</p><h1>冻结第一个位置参数 url</h1><p>github_get = partial(send_request, "<a href="https://www.php.cn/link/e41bbd4af5da30044b88dc9ab711c5b2">https://www.php.cn/link/e41bbd4af5da30044b88dc9ab711c5b2</a>")
print(github_get(method="POST")) # POST <a href="https://www.php.cn/link/e41bbd4af5da30044b88dc9ab711c5b2">https://www.php.cn/link/e41bbd4af5da30044b88dc9ab711c5b2</a> (timeout=10)为什么有时候 partial 后函数签名看起来“不对劲”
partial 对象的 __name__ 和 __doc__ 默认不继承原函数,调试或用 help() 时会看到 <functools.partial at></functools.partial>。这不是 bug,是设计如此——因为偏函数本质是包装器。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 想保留原函数名?手动赋值:
get_with_5s.__name__ = "get_with_5s" - 想带文档?加一句:
get_with_5s.__doc__ = send_request.__doc__ - 更彻底的方案:用
functools.wraps包一层(但partial本身不支持直接装饰,得自己封装)
另外,inspect.signature 看到的参数列表仍是原函数的完整签名,不会自动剔除已冻结参数——这意味着类型检查工具(如 mypy)或 IDE 的参数提示可能不准,得靠人脑补。
partial 和 lambda / 闭包比有什么实际差别
三者都能实现“预设参数”,但行为有微妙区别:
-
lambda x: func(a, b, x)每次调用都重新求值a、b;而partial(func, a, b)在构造时就捕获当前值,更安全(尤其涉及可变对象或闭包变量) -
partial支持func.__dict__、func.__module__等属性透传(部分),lambda 完全没有这些 -
partial对象可被序列化(pickle),lambda 不行 - 性能上差异极小,不用刻意优化,但
partial语义更明确,别人一眼看懂你在“固定参数”
真正容易踩的坑是:误以为 partial 能“动态更新”冻结的值。它不能——所有参数在构造时就定死了,后续修改 a 或 b 的值不影响已创建的 partial 实例。

















