Python类实例化时列表共享问题排查及正确写法问询
问题与解答
问题描述
我有如下类定义:
class Land: id = None blocks = [] class Block: blockId = None blockName = None
我遍历一个JSON数据列表创建包含Block的Land实例,代码逻辑如下:
for value in jsonList: l = Land() l.id = value.id for block in value.blocks: b = Block() blockId = block.id blockName = block.name l.blocks.append(b)
但后续发现数组中的每个Land实例都包含了所有添加过的Block,看起来创建新Land对象时并没有生成新的blocks列表,而是引用了同一个列表。我习惯用C#的new关键字,显然在引用方面存在误解。
补充:
根据相关提示,我是不是应该修改为如下写法?
class Land: def __init__(self): self.id = None self.Blocks = [] class Block: def __init__(self): self.blockId = None self.blockName = None
解答
你的问题核心是混淆了Python中的类变量和实例变量:
- 原来的
Land类里,blocks = []是定义在类层级的类变量,所有Land的实例会共享这个列表对象,所以每次执行l.blocks.append(b)时,都是往同一个全局列表里添加元素,最终导致所有实例的blocks都包含所有Block实例。 - 而C#中在类内声明字段默认是实例专属的,这和Python的类变量行为完全不同,这是你产生误解的根源。
你补充的修改方向完全正确,必须把实例专属的属性放到__init__方法中,用self.xxx来定义,这样每个Land实例创建时都会初始化自己独立的列表(注意你写的是Blocks,和原代码的blocks大小写不一致,保持命名统一即可)。
另外还要修正你创建Block时的小疏漏:你只定义了blockId和blockName两个局部变量,但没有赋值给b的对应属性,应该改成:
b = Block() b.blockId = block.id b.blockName = block.name l.blocks.append(b)
最终正确的代码结构如下:
class Land: def __init__(self): self.id = None self.blocks = [] class Block: def __init__(self): self.blockId = None self.blockName = None # 修正后的实例创建逻辑 for value in jsonList: l = Land() l.id = value.id for block in value.blocks: b = Block() b.blockId = block.id b.blockName = block.name l.blocks.append(b)
这样每个Land实例都会拥有自己独立的blocks列表,不会再出现共享同一列表的问题。
内容的提问来源于stack exchange,提问作者Jason Orman
相关产品推荐
相关产品推荐

