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
相关产品推荐
相关产品推荐

