本篇博客主要讲的是浅拷贝方法,只适用于一维数组中,在多维数组中使用时如果修改复制的数组,原数组也会随之改变。下篇博客python中对列表的复制操作(浅拷贝与深拷贝)讲解浅拷贝与深拷贝之间的区别和用法。
复制列表:
我们经常需要根据既有列表创建全新的列表。下面来介绍复制列表的工作原理,以及复制列表可提供极大帮助的一种情形。
要复制列表,可创建一个包含整个列表的切片,方法是同时省略起始索引和终止索引([:])。这让Python 创建一个始于第一个元素、终止于最后一个元素的切片,即整个列表的副本。
例如,假设有一个列表包含你最喜欢的四种食品,而你想再创建一个列表,并在其中包含一位朋友喜欢的所有食品。不过,你喜欢的食品,这位朋友也都喜欢,因此可通过复制来创建这个列表:
输入一:
```python
my_foods =['pizza','falafel','carrot cake']
friend_foods = my_foods[:]
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)
首先,创建一个你喜欢的食品列表,名为my_foods。然后创建一个名为friend_foods的新列表。在不指定任何索引的情况下从列表my foods中提取一个切片,从而创建这个列表的副本,并将该副本赋给变量 friend_foods。打印这两个列表后,我们发现其包含的食品相同:
结果一:
My favorite foods are:
['pizza', 'falafel', 'carrot cake']
My friend's favorite foods are:
['pizza', 'falafel', 'carrot cake']
为核实确实有两个列表,下面在每个列表中都添加一种食品,并核实每个列表都记录了相应人员喜欢的食品:
输入二:
# my_foods = ['pizza','falafel','carrot cake']
# friend_foods = my_foods[:]
my_foods.append('cannoli') # 新增
friend_foods.append('ice cream') # 新增
# print("My favorite foods are:")
# print(my_foods)
# print("\nMy friend's favorite foods are:")
# print(friend_foods)
与前一个示例一样,首先将my_foods的元素复制到新列表friend_foods中。接下来,在每个列表中都添加一种食品:在列表 my_foods 中添加’cannoli’,而在 friend_foods中添加’ice cream’。最后,打印这两个列表,核实这两种食品分别包含在正确的列表中。
结果二:
My favorite foods are: # 1
['pizza', 'falafel', 'carrot cake', 'cannoli']
My friend's favorite foods are: # 2
['pizza', 'falafel', 'carrot cake', 'ice cream']
1处的输出表明,’cannoli’包含在你喜欢的食品列表中,而’ice cream‘不在。2处的输出表明,'ice cream’包含在你朋友喜欢的食品列表中,而’cannoli‘不在。如果只是将my_foods赋给friend foods,就不能得到两个列表。例如,下面演示了在不使用切片的情况下复制列表的情况:
输入三:
# my_foods = ['pizza','falafel','carrot cake']
# friend_foods = my_foods[:]
# 这行不通
# 1
friend_foods = my_foods
# my_foods.append('cannoli') # 新增
# friend_foods.append('ice cream') # 新增
# print("My favorite foods are:")
# print(my_foods)
# print("\nMy friend's favorite foods are:")
# print(friend_foods)
这里将my_foods 赋给friend foods,而不是将my_foods的副本赋给friend foods(见1)。这种语法实际上是让 Python将新变量friend_foods关联到已与my_foods相关联的列表,因此这两个变量指向同一个列表。有鉴于此,当我们将“cannoli’添加到 my_foods 中时,它也将出现在friend_foods 中。同样,虽然’ice cream’好像只被加入到了friend_foods中,但它也将出现在这两个列表中。
输出表明,两个列表是相同的,这并非我们想要的结果:
结果三:
My favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']
My friend's favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']
注意:暂时不要考虑这个示例中的细节。当试图使用列表的副本时结果出乎意料,基本上都要
确认你是否像第一个示例那样使用切片复制了列表。
禁止函数修改列表(刷题时经常会遇到这种问题):
示例:
def print_models(unprinted_designs, completed_models):
'''
模拟打印每个设计,直到没有未打印的设计为止。
打印每个设计后,都将其移到列表completed_models中。
'''
while unprinted designs:
current_design = unprinted_designs.pop()
print(f"Printing model: {current_design}")
completed models.append(current_design)
def show_completed_models(completed_models):
'''显示打印好的所有模型。'''
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)
有时候,需要禁止函数修改列表。例如,像示列那样,你有一个未打印的设计列表,并编写了一个函数将这些设计移到打印好的模型列表中。你可能会做出这样的决定:即便打印好了所有设计,也要保留原来的未打印的设计列表,以供备案。但由于你将所有的设计都移出了 unprinted_designs,这个列表变成了空的,原来的列表没有了。为解决这个问题,可向函数传递列表的副本而非原件。这样,函数所做的任何修改都只影响副本,而原件丝毫不受影响。
要将列表的副本传递给函数,可以像下面这样做:
function_name(list_name[:])
切片表示法[:]创建列表的副本。在 示列中,如果不想清空未打印的设计列表,可像下面这样调用 print_models():
print_models(unprinted_designs[:], completed_models)
这样函数print_models()依然能够完成工作,因为它获得了所有未打印的设计的名称,但使用的是列表unprinted_designs的副本,而不是列表unprinted_designs本身。像以前一样,列表completed_models也将包含打印好的模型的名称,但函数所做的修改不会影响到列表unprinted_designs。
虽然向函数传递列表的副本可保留原始列表的内容,但除非有充分的理由,否则还是应该将原始列表传递给函数。这是因为让函数使用现成的列表可避免花时间和内存创建副本,从而提高效率,在处理大型列表时尤其如此。