Python 默认参数:为什么列表会记住上一次调用?

举报
yd_239549656 发表于 2026/11/02 09:17:29 2026/11/02
【摘要】 用连续两次调用复现可变默认参数共享,比较 None 初始化,并验证显式传入空列表时的对象身份,避免用 or [] 悄悄改变接口行为。

函数第一次返回一个主题列表,第二次调用时却带上了第一次的内容。排查这种现象时,需要检查列表是在函数体内创建,还是写在参数默认值里。

1. 两次调用共用了一份列表

下面使用完全独立构造的数据,不读取文件或业务信息:

def add_topic_bad(topic, topics=[]):
    topics.append(topic)
    return topics

first = add_topic_bad("python")
second = add_topic_bad("csv")
print(first is second)
print(first)

输出:

True
['python', 'csv']

这里不仅是两个结果内容相同。first is second 为 True,说明它们引用同一个列表。第二次 append 也改变了 first 仍然引用的对象。

Python 在执行函数定义时求值默认参数表达式,不会在每次省略参数的调用中重新执行 topics=[]。因此,该函数定义产生的默认列表被后续省略此参数的调用复用。这项规则在 Python 官方教程与编程 FAQ 中都有说明。

2. 在需要时创建新列表

若接口约定“未提供列表时,每次创建一份”,可以使用 None 表达这个条件:

def add_topic(topic, topics=None):
    if topics is None:
        topics = []
    topics.append(topic)
    return topics

left = add_topic("python")
right = add_topic("csv")
print(left is right)
print(left, right)

provided = []
returned = add_topic("git", provided)
print(returned is provided, provided)

输出:

False
['python'] ['csv']
True ['git']

前两次调用分别走入初始化分支,得到独立列表。最后一次显式传入 provided,函数仍在调用者的列表上追加数据,返回的也是同一对象。

3. 不要把两种接口约定混在一起

is None 只判断是否使用约定的缺省标记。如果改写为 topics = topics or [],空列表也会进入替换分支;调用者传入的空列表不再是被修改和返回的那一个对象。若接口承诺原地追加,这样的简写就改变了行为。

同样,使用 None 初始化只消除了省略参数时的意外共享,并没有承诺“不修改调用者传入的列表”。如果需要后一种行为,应另行设计复制策略,并明确嵌套对象的处理方式。

当 None 本身也是合法业务数据时,还需要独立的缺省标记。本例将 None 明确定义为“创建新列表”,没有覆盖那种接口。

4. 验证范围

本次在本机 Python 3.9.6 中直接执行上述两段代码,打印结果与文中输出一致;十项断言覆盖默认列表共享、两次缺省调用独立、显式空列表原地修改、非空列表保留已有元素,以及显式传入 None 时重新创建列表。样例只覆盖普通列表、字符串和 None,不涉及并发、缓存或自定义容器。

官方参考:

  • Python 编程 FAQ:docs.python.org/3/faq/programming.html#why-are-default-values-shared-between-objects
  • Python 教程默认参数:docs.python.org/3/tutorial/controlflow.html#default-argument-values

本文由 AI 辅助整理,示例数据为独立构造,并已在本机执行自检。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。