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

Python递归调用中为何未实例化新Configer对象?

Python可变默认参数导致的意外行为分析

问题重现

你遇到的代码及测试结果如下:

代码示例

class Configer(object):
    
    def __init__(self, pops_cfg = {}):
        self.pops_cfg = pops_cfg
        
    
    def add_pop(self, name, gs):
        pop_cfg = {}
        pop_cfg['gs'] = gs
        
        if name in self.pops_cfg:
            self.pops_cfg[name].update(pop_cfg)
        else:
            self.pops_cfg[name] = pop_cfg
        
    def get(self):
        return self.pops_cfg
    

def get_config(name):    
    if name == 'I':
        c = Configer()
        c.add_pop('I', 100)
        
    elif name == 'IE':
        c = get_config('I')
        c.add_pop('E', 200)
    
    else:
        raise
        
    return c

测试用例及结果

# test 1
a = get_config('I')
print(a, id(a), a.get())
# <__main__.Configer object at 0x7fa83615c580> 140360438629760 {'I': {'gs': 100}}

# test 2
b = get_config('IE')
print(b, id(b), b.get())
# <__main__.Configer object at 0x7fa83603f610> 140360437462544 {'I': {'gs': 100}, 'E': {'gs': 200}}

# test 3
c = get_config('I')
print(c, id(c), c.get())
# <__main__.Configer object at 0x7fa83603c280> 140360437449344 {'I': {'gs': 100}, 'E': {'gs': 200}}

测试1、2结果符合预期,但测试3与测试1调用逻辑一致,却返回包含两个键的对象。

原因解析

问题根源在Configer.__init__的可变默认参数上:

Python中,函数的默认参数是在函数定义时创建的,而非每次调用时重新生成。对于字典这类可变对象来说,所有不带参数调用Configer()的实例,都会共享同一个字典对象。

具体流程拆解:

  1. 测试1调用get_config('I'),创建Configer实例a,a.pops_cfg指向定义__init__时生成的空字典,调用add_pop后该共享字典变为{'I': {'gs': 100}}。
  2. 测试2调用get_config('IE'),内部调用get_config('I')创建新实例b,b.pops_cfg仍指向那个已修改的共享字典,调用add_pop后字典变为{'I': {'gs': 100}, 'E': {'gs': 200}}。
  3. 测试3调用get_config('I')创建新实例c,c.pops_cfg还是引用这个共享字典,因此返回结果包含两个键。

注意:每个实例的id不同是因为每次都生成了新的Configer对象,但它们的pops_cfg属性都指向同一个共享字典。

修复方案

将可变默认参数替换为None,在__init__内部创建新的空字典,确保每次调用Configer()时生成独立的字典:

class Configer(object):
    
    def __init__(self, pops_cfg=None):
        if pops_cfg is None:
            pops_cfg = {}
        self.pops_cfg = pops_cfg
        
    # add_pop、get方法保持不变

修改后再运行测试,测试3的返回结果会是{'I': {'gs': 100}},符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 05:10:55