You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python函数调用间可变默认参数memo未清空的原因咨询

问题根因

这个现象是Python函数默认参数的既定设计规则导致的,和递归逻辑本身无关:

  • 函数的默认参数值只会在函数定义完成时被求值、创建一次,不会在每次函数调用时重新生成新的对象
  • 当默认参数是不可变类型(整数、字符串、None、元素全为不可变类型的元组)时,因为无法原地修改对象本身,日常编码中几乎感知不到这个复用逻辑
  • 当默认参数是可变类型(字典、列表、集合等)时,函数内部对该参数的所有原地修改(比如给字典新增键值对、给列表追加元素)都会永久保留在这个唯一的默认参数对象上,下次调用不传对应参数时,拿到的就是上一次调用修改后的对象,这就是你遇到的memo缓存跨调用残留的原因。

你可以用一段极简代码验证这个逻辑:

def demo(memo = {}):
    # 打印对象内存地址,相同地址代表是同一个对象
    print(f"当前memo对象的内存id: {id(memo)}")
    memo["call_count"] = memo.get("call_count", 0) + 1
    print(f"memo内存储的值: {memo}")

# 连续两次调用,都不传memo参数
demo()
demo()

运行后你会看到两次打印的内存id完全一致,第二次调用时直接拿到了第一次调用修改后的字典,计数变成2,和你遇到的现象完全匹配。

修复方案原理

你找到的memo=None写法是这类场景的标准处理方式:

def canSum(targetSum, nums, memo = None):
    if memo is None:
        # 空字典是在函数调用执行到这一行时才创建的,每次调用都会生成新的独立字典
        memo = {}
    # 后续原有逻辑不变
    if targetSum in memo:
        return memo[targetSum]
    if targetSum == 0: return True
    if targetSum < 0: return False

    for num in nums:
        remainder = targetSum - num
        if canSum(remainder, nums, memo):
            memo[targetSum] = True
            return True

    memo[targetSum] = False
    return False

这里用不可变值None作为默认参数,不存在被原地修改的可能,每次调用不传memo时,都会进入判断分支新建一个属于当次调用的空字典,从根源上避免了可变默认参数被复用导致的缓存串值问题。

注意这里判断建议用if memo is None而不是if memo == None,前者是对象身份判断,性能更好也更符合Python官方编码规范。

内容的提问来源于stack exchange,提问作者Chiken

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:57:13