Python 语法精炼5
星号表达式与解包
*args:函数接收任意位置参数
作用:把额外的位置参数收集为一个 tuple。
1 | def summarize(*args): |
要点
*args可以出现在参数列表中任意位置,但惯例写在普通位置参数之后、关键字参数之前:def f(a, b, *args, kw=0):- 在函数内部,
args是tuple(不可变)。 - 多个星号参数不允许(只能有一个
*捕获位置参数)。
常见用法
- 聚合任意数量的位置参数(统计、拼接等)。
- 与普通参数组合,做默认或强制参数数量检查。
注意:
*args捕获的是位置参数,不会捕获以name=value形式传入的关键字参数(那些会进**kwargs)。
**kwargs:函数接收任意关键字参数
作用:把额外的关键字参数收集为一个 dict。
1 | def show(**kwargs): |
要点
**kwargs必须放在参数列表的最后(在*args之后)。- 内部是
dict,键为传入的参数名(字符串),值为对应值。 - 可结合显式关键字参数:
def f(x, **kw):
常见用法
- 接受灵活的配置选项。
- 把参数透传给别的函数:
other_func(**kwargs)
坑 / 注意
- 在调用时
**解包的字典中键必须是字符串且是合法的标识符(否则作为关键字参数会失败);例如f(**{'1': 2})会报错(非法关键字名)。 - 函数调用时,如果同时显式传入了和
**dict中重复的关键字,会产生 “multiple values for argument” 的错误(或最后一个覆盖,视目标函数签名而定)—小心显式位置/关键字与解包字典的冲突。
用 * / ** 进行解包
作用:把序列或映射展开成函数的参数。
1 | def f(a, b, c): |
要点
*iterable:将可迭代对象按位置展开(数量 & 顺序必须匹配位置参数)。**mapping:将映射展开为关键字参数(映射的 keys 必须为合适的标识符,与目标参数名匹配)。- 可以同时用:
f(*args, **kwargs)。
进阶
- Python 支持在函数调用时使用多个
*和**(从 Python 3.5+ PEP 448),例如f(*a, *b)、f(**d1, **d2)—— 最终传入的参数由左向右合并(后面的覆盖前面的,注意与显式传参冲突的情况)。
坑 / 注意
- 如果函数签名已经通过位置或关键字给定了同名参数,额外的解包可能会导致
TypeError: multiple values for argument 'x'。 - 合并大量大字典/列表会临时分配新对象,注意内存开销。
用 * / ** 进行赋值
作用:在赋值时收集中间元素到列表。
1 | a, *middle, c = [0, 1, 2, 3, 4] |
要点
- 左侧允许一个
*name用于捕获剩余元素,结果是list(即使原来是 tuple/iterable)。 *可以出现在任意位置:首、中、尾(如*head, tail = ...)。- 仅 一个 starred target 被允许在赋值语句左侧。
常见用法
- 取首尾、弹性匹配。
- 在递归函数中将可迭代拆成首元素 + 剩余列表。
用 * / ** 合并容器
列表/元组合并(Python 3.5+)
1 | a = [1, 2] |
字典合并(Python 3.5+ 用 **,3.9+ 有 |)
1 | d1 = {'x': 1} |
要点
- 在字典字面量中使用
**是很常用的模式来合并/覆盖配置。 - 多个
*/**按顺序展开,后者覆盖前者同名键。
坑 / 注意
- 合并大量大容器会产生临时对象(内存/性能考虑)。
- 字面量解包要求被解包对象是可迭代或映射,否则会报错。
注意事项
*args内部是tuple(不可变)——如果需要列表操作,list(args)一次性复制。{**d1, **d2}会创建新dict,不是原地修改(如果想就地修改用d1.update(d2))。[*a, *b]创建新列表;若想减少内存分配,考虑使用迭代器或itertools.chain。
常见模式
- 透传参数(decorator / wrapper):
1 | def wrapper(func): |
- 合并配置:
1 | defaults = {'timeout': 30, 'retries': 3} |
- 可变参数收集与强制关键词参数:
1 | def f(a, b, *, verbose=False): |
- 灵活地拆分序列:
1 | first, *rest = data |
常见问题
- SyntaxError:在赋值左侧用多个
*。 - TypeError: f() got multiple values for argument ‘x’:通常是位置参数、命名参数与解包字典的键重复导致,检查调用处的参数来源。
- KeyError / invalid keyword:
f(**d)的字典键必须是字符串且是合法标识符(不能含空格、不能以数字开头等);若键不是合法标识符,不能直接**解包到关键字参数。 - 性能:避免在热路径频繁创建大临时容器(
[*a, *b]、{**d1, **d2});改用迭代器或 in-place 更新(extend/update)如果可行。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Telason!
