在Python中,列表的赋值操作(尤其是使用列表推导式)有时会产生意外的副作用,特别是在涉及可变对象(如列表或字典)时。在你给出的代码片段中,问题出在这行代码:
self.hanayo_list = [self.lay_info_list for _ in range(2)]
这里,self.lay_info_list
是一个包含四个可变对象(列表、字典、元组和字典)的列表。当你使用列表推导式创建 self.hanayo_list
时,你实际上是在创建一个包含两个指向 self.lay_info_list
的引用的列表,而不是创建两个独立的列表副本。
这意味着 self.hanayo_list[0]
和 self.hanayo_list[1]
都指向同一个 self.lay_info_list
实例。因此,当你对 self.hanayo_list[0]
中的任何可变对象进行修改时,self.hanayo_list[1]
也会反映出这些修改。
具体到你的代码,当执行以下操作时:
self.hanayo_list[0][0].append(module)
你实际上是在 self.lay_info_list[0]
(它是一个列表)中添加了一个新元素。因为 self.hanayo_list[0]
和 self.hanayo_list[1]
都引用同一个列表,所以 self.hanayo_list[1][0]
的长度也会增加。
要解决这个问题,你需要确保 self.hanayo_list
中的每个元素都是 self.lay_info_list
的独立副本。你可以通过使用深拷贝来实现这一点:
import copy
self.hanayo_list = [copy.deepcopy(self.lay_info_list) for _ in range(2)]
这样,self.hanayo_list[0]
和 self.hanayo_list[1]
将会是两个独立的列表,对其中一个的修改不会影响另一个。请注意,深拷贝可能会引入额外的性能开销,特别是在处理大型或复杂的对象时。
创建独立的副本
- 使用列表推导式和对象构造器:对于简单对象,可以在列表推导式中使用对象的构造器来创建新的实例。
self.hanayo_list = [[[] for _ in range(len(self.lay_info_list[0]))],
[{} for _ in range(len(self.lay_info_list[1]))],
[() for _ in range(len(self.lay_info_list[2]))],
[{} for _ in range(len(self.lay_info_list[3]))]]
- 使用深拷贝:对于复杂对象,使用
copy.deepcopy()
来确保每个元素都是独立的。
import copy
self.hanayo_list = [copy.deepcopy(self.lay_info_list) for _ in range(2)]
使用不可变对象
- 尽可能使用不可变对象(如元组而不是列表),这样赋值就不会产生副作用。
明确的复制操作
- 使用
list()
、dict()
等构造器来创建对象的显式副本。
self.hanayo_list = [list(self.lay_info_list[0]), dict(self.lay_info_list[1]), self.lay_info_list[2], dict(self.lay_info_list[3])]
请注意,上述方法中 list()
和 dict()
只会创建浅拷贝。如果列表或字典包含可变对象,你可能仍然需要使用 copy.deepcopy()
。
使用工厂函数
- 创建一个工厂函数来创建列表的副本。
def create_lay_info():
return [[], {}, (), {}]
self.hanayo_list = [create_lay_info() for _ in range(2)]
通过遵循这些实践,你可以避免在Python中处理列表和其他可变对象时遇到的常见陷阱。