Python 提供了多种有效的方法来管理数据。在处理嵌套列表、字典或自定义对象等数据结构时,理解浅复制和深复制的概念是至关重要的。

使用浅复制

浅复制通过创建原始对象的顶层结构的副本来工作。这意味着如果原始对象包含嵌套对象,复制将引用与原始对象相同的嵌套对象。换句话说,对对象进行浅复制会复制其最外层结构,而不会复制它可能包含的任何嵌套对象。

要在 Python 中执行浅复制,您可以使用 copy 模块的 copy() 函数或对象上的 .copy() 方法。

考虑一个在 Python 中使用列表或字典的示例。

# Linux迷 www.linuxmi.com
import copy

main_list = [29, 49, ["Q", "R"]]
shallow_copy = copy.copy(main_list)

# 修改嵌套列表
shallow_copy[2][0] = 99
main_list[2][1] = 100

print(f"The main list: {main_list}")
print(f"The shallow copy list: {shallow_copy}")

上面的代码中,main_list 变量包含一个包含整数和包含字母的内部列表(嵌套对象)。copy 函数创建了 main_list 的副本,代码将其存储在另一个变量 shallow_copy 中。

您对 shallow_copy 嵌套列表所做的任何更改也将直接影响到 main_list,反之亦然。这些更改表明 shallow_copy 的嵌套或内部列表只是对 main_list 的引用,使更改也适用于 main_list。

与此同时,对 shallow_copy 或 main_list 中的外部项(整数)所做的任何更改仅会影响该实例。这些外部项本质上是独立的值,而不仅仅是引用。

# Linux迷 www.linuxmi.com
import copy

main_list = [29, 49, ["Q", "R"]]
shallow_copy = copy.copy(main_list)

# 修改外部项
shallow_copy[0] = "M"
main_list[1] = "N"

print(f"The main list: {main_list}")
print(f"The shallow copy list: {shallow_copy}")

输出表明两个列表的外部项是彼此独立的:

对浅复制的外部项进行更改

在处理字典时,相同的理念也适用。

# Linux迷 www.linuxmi.com
dict1 = {'ten': 10, 'twenty': 20, 'double':{'thirty': 30, 'sixty': 60}}
dict2 = dict1.copy()

# 修改内部和外部元素
dict1['double']['thirty'] = 30.00
dict1['ten'] = 10.00

print(f"The main dictionary, {dict1}")
print(f"The shallow copy dictionary, {dict2}")

对 dict1 的嵌套字典进行的更改会影响 dict1 和 dict2。与此同时,对 dict1 的外部项进行的更改只会影响 dict1。

使用嵌套字典的浅复制

使用深复制

深复制不是引用原始复制的嵌套对象,而是完全单独复制原始对象及其嵌套对象。对深复制的修改不会影响原始对象,反之亦然;它们是真正独立的值。

要在Python中创建深度复制,可以使用copy模块的deepcopy()函数。

考虑一个使用列表的示例。

# Linux迷 www.linuxmi.com
import copy

main_list = [200, 300, ["I", "J"]]
deep_copy = copy.deepcopy(main_list)

# 修改内部和外部列表
deep_copy[2][0] = "K"
main_list[0] = 500

print(f"主列表:{main_list}")
print(f"深度复制列表:{deep_copy}")

在这里,代码执行了main_list的深度复制,创建了一个名为deep_copy的独立副本。

当您修改deep_copy中的嵌套列表或外部项时,您的更改不会影响原始列表,反之亦然。这表明嵌套列表或外部元素不在两个副本之间共享。

处理自定义对象

您可以通过定义Python类并创建类的实例来创建自定义对象。

以下是从Book类创建一个简单对象的示例:

class Book:
def __init__(self, title, authors, price):
self.title = title
self.authors = authors
self.price = price

def __str__(self):
return f"Book(title='{self.title}', author='{self.authors}', \
price='{self.price}')"

现在,使用copy模块对这个Book类的实例分别进行浅复制和深复制。

import copy

# 创建一个Book对象
book1 = Book("www.linuxmi.com 如何利用浅拷贝", \
["Bobby Jack", "Princewill Inyang"], 1000)

# 进行浅复制
book2 = copy.copy(book1)

# 修改原始对象
book1.authors.append("Yuvraj Chandra")
book1.price = 50

# 检查对象
print(book1)
print(book2)

如您所见,浅复制(book2)是一个新对象,但它引用与原始对象(book1)相同的内部对象(作者列表)。因此,对原始对象的作者进行的更改会影响两个实例(book1和book2),而对外部项(价格)的更改只会影响原始对象(book1)。

另一方面,进行深复制会创建原始对象的独立副本,包括其中包含的所有对象的副本。

# 创建一个Book对象
book1 = Book("www.linuxmi.com 如何利用浅拷贝?", \
["Bobby Jack", "Yuvraj Chandra"], 5000)

# 进行深复制
book2 = copy.deepcopy(book1)

# 修改原始对象
book1.authors.append("Princewill Inyang")
book1.price = 60

# 检查对象
print(book1)
print(book2)

在这种情况下,深复制(book2)是一个完全独立的对象,对原始对象(book1)的修改不会影响它。

使用浅复制和深复制的用途

了解深度和浅复制非常重要,以便您可以选择适当的方法来操作数据。以下是适用于每种方法的一些情况:

  • 如果您想要复制一个复杂对象而不生成其嵌套对象的新实例,则使用浅复制。这种方法比深复制更节省内存并且更快,因为它不会复制嵌套对象。
  • 如果您想要创建对象状态的快照,同时仍然在原始对象和复制对象之间共享一些基础数据,则使用浅复制。
  • 如果您想要修改对象的副本而不影响原始对象,则使用深复制。这会生成独立的嵌套对象的副本,确保对副本的任何更改不会应用于原始对象。
  • 当您需要独立副本的嵌套数据结构时,特别是在处理递归或复杂的对象层次结构时,深复制非常重要。

性能和注意事项

由于浅复制不生成嵌套对象的新实例,因此通常比深复制运行速度更快,使用的内存更少。然而,原始对象和浅复制可能会因更改共享的内部项目而产生不希望的副作用。

特别是对于大型和深度嵌套的数据结构,深复制是一个递归过程,可能会更慢,使用更多内存。然而,它确保了原始对象和深度副本之间的完全独立性,使复杂的数据操作更加安全。

选择适合您数据的最佳复制选项 许多编程语言都使用浅复制和深复制的概念。了解这一概念使您能够在没有意外后果的情况下操作数据。

通过使用浅复制和深复制技术,您可以选择最安全地复制数据结构的最佳方法。通过了解对数据的影响,您将从代码中获得更可靠和可预测的结果。

发表回复