在添加新元素时,由两个(或多个)引用原始列表的列表组成一个列表



我想创建一个对象列表,它代表具有相同属性的对象的整个类别(假设是可见的对象)。但是,一旦我将对象追加到其中一个子组,它就不会更新所有可见对象的列表(visible_objects)。这对我来说是已知的Python行为,但我想知道实现这一点的最佳实践是什么,所以它以干净无缝的方式将元素也附加到组合列表(visible_objects)。(例如,每当我将新元素添加到其中一个子组时)

class A:
def __init__(self,i):
self.i=i

images=[A(1),A(2),A(3)]
images2=[A(4),A(5)]
visible_objects=images+images2
images.append(A(6))
print([x.i for x in images])
print([x.i for x in images2])
print([x.i for x in visible_objects])
[1, 2, 3, 6]
[4, 5]
[1, 2, 3, 4, 5]

我希望最后一个列表也包含6没有重新分配visible_objects后每次追加。非常感谢。

好的,我想我算是解决了这个问题,但我不确定这是不是最好的方法。

class A:
def __init__(self,i):
self.i=i

class MagicList:
def __init__(self,elements=[],referenced_lists=None):
self.elements=elements
self.referenced_lists=referenced_lists
self.embedded_in_lists=[]
if self.referenced_lists is not None:
self.elements=[]
for i,magic_list in enumerate(self.referenced_lists):
for item in magic_list.elements:
self.elements.append(item)
self.referenced_lists[i].embedded_in_lists.append(self)

def append(self,obj):
self.elements.append(obj)
for i,list1 in enumerate(self.embedded_in_lists):

self.embedded_in_lists[i].elements=[]
for j in range(len(list1.referenced_lists)):
self.embedded_in_lists[i].elements+=list1.referenced_lists[j].elements

def pop(self,index):
self.elements.pop(index)
for i,item in enumerate(self.embedded_in_lists):
item.elements.pop(index)

def __str__(self):
return(str(self.elements))


m=MagicList([1,3,4])
m2=MagicList([2,5,8]) 
m3=MagicList(referenced_lists=[m,m2])
print(m)
print(m2)
print(m3) 

images=MagicList([A(1),A(2),A(3)])
images2=MagicList([A(4),A(5)])
visible_objects=MagicList(referenced_lists=[images,images2])
print([x.i for x in images.elements])
print([x.i for x in visible_objects.elements])
images.append(A(6))
print([x.i for x in images.elements])
print([x.i for x in visible_objects.elements])
images.pop(3)
print([x.i for x in images.elements])
print([x.i for x in visible_objects.elements])

结果:

[1, 3, 4]
[2, 5, 8]
[1, 3, 4, 2, 5, 8]
[1, 2, 3]
[1, 2, 3, 4, 5]
[1, 2, 3, 6]
[1, 2, 3, 6, 4, 5]
[1, 2, 3]
[1, 2, 3, 4, 5]

您的答案是一个很好的方法,但是您也可以通过在MagicList中定义返回正确元素的__getitem__()来实现这一点。这样,您就不需要花时间将每个列表中的元素克隆或复制到一个大的"超级列表"中,也不需要花时间修改"子列表"。当您尝试获取MagicList对象的索引时,将无缝地反映

class MagicList():
def __init__(self, *referenced_lists):
self.lists = referenced_lists

def __getitem__(self, index):
cum_len = 0
for sublist in self.lists:
sublist_start_index = cum_len
sublist_end_index = cum_len + len(sublist)
if sublist_end_index > index:
return sublist[index - sublist_start_index]
cum_len = sublist_end_index
raise IndexError("list index out of range")
def __str__(self):
return str([x for x in self])
def add_list(self, new_list):
if isinstance(new_list, list): # If new_list is a list, append it to self.lists
self.lists.append(new_list)
else: # Try to convert new_list to a list and append that
try:
self.lists.append(list(new_list))
except TypeError: # new_list is not an iterable, so list(new_list) throws a TypeError
self.lists.append([new_list])

然后,你可以这样做:

l1  = [1, 2, 3, 4, 5]
l2 = [100, 200, 300, 400, 500]
m = MagicList(l1, l2) # You can give this any number of lists
print("Original list: ")
print(m)
l1.append(-1)
print("Appending to l1: ")
print(m)
l2.append(1000)
print("Appending to l2: ")
print(m)
l1[0] = 'abc'
print("Modifying l1: ")
print(m)
l2[-2] = 'def'
print("Modifying l2: ")
print(m)
del l1[0]
print("Removing from l1: ")
print(m)
del l2[-1]
print("Removing from l2: ")
print(m)

输出如下:

Original list: 
[1, 2, 3, 4, 5, 100, 200, 300, 400, 500]
Appending to l1: 
[1, 2, 3, 4, 5, -1, 100, 200, 300, 400, 500]
Appending to l2: 
[1, 2, 3, 4, 5, -1, 100, 200, 300, 400, 500, 1000]
Modifying l1: 
['abc', 2, 3, 4, 5, -1, 100, 200, 300, 400, 500, 1000]
Modifying l2: 
['abc', 2, 3, 4, 5, -1, 100, 200, 300, 400, 'def', 1000]
Removing from l1: 
[2, 3, 4, 5, -1, 100, 200, 300, 400, 'def', 1000]
Removing from l2: 
[2, 3, 4, 5, -1, 100, 200, 300, 400, 'def']

一些要记住的东西:如果你想添加/插入任何不在引用列表中的MagicList,你需要将其包装在列表中。

最新更新