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

Python实例属性声明问题:TestItems的items列表被多实例共享原因排查

Python实例共享可变默认参数的问题分析与修复

问题场景

你定义了两个类TestItem和TestItems,尝试创建多个TestItems实例并分别导入数据,却发现所有实例的items列表被意外共享了:

你的代码

class TestItem(object):
    def __init__(self):
        super(TestItem, self).__init__()
    def import_(self, value):
        self.value = value
class TestItems(object):
    def __init__(self, items=[]):
        super(TestItems, self).__init__()
        self.items = items
    def __getitem__(self, index):
        return self.items[index]
    def __len__(self):
        return len(self.items)
    def import_from_list(self, data):
        for i in data:
            item = TestItem()
            item.import_(i)
            self.items.append(item)
data = []
data.append(TestItems())
data[-1].import_from_list(['A', 'B'])
for i, j in enumerate(data):
    print('Size of data[%i] - %i' % (i, len(j)))
data.append(TestItems())
data[-1].import_from_list([1, 2])
for i, j in enumerate(data):
    print('Size of data[%i] - %i' % (i, len(j)))
    print('First element of data[%i] - %s' % (i, j[0].value))
print(data[0])
print(data[1])

运行输出

Size of data[0] - 2
Size of data[0] - 4
First element of data[0] - A
Size of data[1] - 4
First element of data[1] - A
<__main__.TestItems object at 0x000002C0765F51D0>
<__main__.TestItems object at 0x000002C0765F52B0>

可以看到两个不同的TestItems实例,它们的items列表长度都是4,且第一个元素都是A,这显然不符合每个实例独立管理数据的预期。


问题根源:可变默认参数的经典陷阱

这是Python里非常常见的坑——可变默认参数(比如列表、字典这类可修改对象)会在函数/方法定义时就完成初始化,而不是每次调用时重新创建。

在你的TestItems类的__init__方法里,items=[]这个默认参数,会在Python加载这个类的时候就创建一个空列表对象。之后每次调用TestItems()(不传items参数时),都会直接复用这个已经存在的列表,而不是新建一个。

所以第一个TestItems实例调用import_from_list往self.items里添加元素时,第二个实例的self.items其实指向的是同一个列表,自然会共享所有元素。


你的修复方案完全正确!

你改成以下代码后成功解决了问题:

class TestItems(object):
    def __init__(self, items=None):
        super(TestItems, self).__init__()
        self.items = items or []

为什么这个方法有效?

  • 当不传items参数时,items会被设为None,items or []会创建一个全新的空列表,每个TestItems实例都会拥有自己独立的items列表。
  • 如果传入了非空的items参数,则直接使用传入的列表;如果传入的是空列表,items or []也会创建新的空列表(若你想保留传入空列表的行为,改用if items is None的判断会更精确)。

补充:更严谨的写法(可选)

如果你想避免传入的外部列表被实例的操作意外修改(比如实例调用append会改变原列表),可以改成更明确的判断,并且对传入的列表做浅拷贝:

def __init__(self, items=None):
    super(TestItems, self).__init__()
    if items is None:
        self.items = []
    else:
        # 浅拷贝,确保实例的items和外部传入的列表彻底独立
        self.items = list(items)

这样无论是否传入参数,每个实例的items都是独立的,不会影响外部数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:42:29