python 赋值 深浅拷贝

Python赋值是编程过程中的一项基本操作。在Python中,赋值可分为深度拷贝和浅度拷贝两种类型。本文将详细介绍Python中的深度拷贝和浅度拷贝,并通过代码展示它们之间的区别和使用情况。

1. 赋值操作简介

在Python中,赋值是一种操作符。它可以将某一个对象赋值给一个变量或者一个表达式,例如:a=5。在此例子中,5被赋值给变量a。赋值操作可以通过以下方式实现:

a = 5

b = 'hello'

c = [1, 2, 3]

1.1. 不可变类型和可变类型

Python中的对象可以分为两种类型:不可变类型和可变类型。不可变类型是指一旦对象被创建,它们的值就无法更改,例如字符串和元组。相反,可变类型是指对象的值可以更改,例如列表和字典。

以下是Python的一些不可变类型:

a = 5 #整数

b = 3.1415 #浮点数

c = True #布尔型

d = 'hello' #字符串

e = (1, 2, 3) #元组

以下是Python的一些可变类型:

a = [1, 2, 3] #列表

b = {'name': 'Jerry', 'age': 20} #字典

2. 浅拷贝(Shallow Copy)

浅拷贝是在Python中复制对象的一种方式。它创建了一个新对象,其中包含了原始对象的引用。新对象和原始对象共享一个内存地址。如果原始对象发生更改,它的所有浅拷贝都会反映这些更改。

下面我们来看一个浅拷贝的例子:

#浅拷贝列表

a = [1, 2, 3]

b = a.copy()

print(b) #[1, 2, 3]

#修改原始列表

a[0] = 'hello'

print(a) #['hello', 2, 3]

#浅拷贝后的列表也被修改了

print(b) #[1, 2, 3]

在这个例子中,我们使用了列表的copy()方法进行浅拷贝操作。我们更改了原始列表a的第一个索引,然后检查了浅拷贝后的b列表。由于b只是a的引用,所以b的内容也被更改了。

因为浅拷贝共享原始对象的内存地址,如果原始对象是可变类型,当它被更改时,所有的浅拷贝都会受到影响。

2.1. 浅拷贝的方式

Python提供了三种浅拷贝的方式:

2.1.1. 切片操作

切片操作[:]是Python中最简单的浅拷贝方法。它可以创建一个新的对象,其中包含原始对象的所有元素。

以下是一个使用切片操作进行浅拷贝的例子:

a = [1, 2, 3]

b = a[:]

print(b) #[1, 2, 3]

#修改原始列表

a[0] = 'hello'

print(a) #['hello', 2, 3]

#浅拷贝后的列表没有被修改

print(b) #[1, 2, 3]

在这个例子中,我们使用了切片操作来浅拷贝列表。当我们更改原始列表a的第一项时,浅拷贝后的b列表并没有受到影响。这是因为切片操作创建了一个新的列表,而不是一个指向原始列表的引用。

2.1.2. 工厂函数

Python提供了一些工厂函数,例如list()和dict()。这些函数可以用于浅拷贝对象。

以下是一个使用list()方法浅拷贝的例子:

a = [1, 2, 3]

b = list(a)

print(b) #[1, 2, 3]

#修改原始列表

a[0] = 'hello'

print(a) #['hello', 2, 3]

#浅拷贝后的列表没有被修改

print(b) #[1, 2, 3]

在这个例子中,我们使用了list()方法来浅拷贝列表a。与切片操作类似,这创建了一个新的列表。

2.1.3. copy()方法

大多数Python对象都有一个名为copy()的方法。这个方法可以用于浅拷贝对象。

以下是一个使用copy()方法浅拷贝的例子:

a = [1, 2, 3]

b = a.copy()

print(b) #[1, 2, 3]

#修改原始列表

a[0] = 'hello'

print(a) #['hello', 2, 3]

#浅拷贝后的列表没有被修改

print(b) #[1, 2, 3]

在这个例子中,我们使用了copy()方法来浅拷贝列表a。

2.2. 浅拷贝的应用场景

浅拷贝最常见于对元组、列表和字典等可变对象的复制,以防止在修改原始对象时意外更改其他对象。但是,如果原始对象包含不可变对象,则浅拷贝非常有用。在这种情况下,浅拷贝将复制对象的引用,这可以节省内存。

3. 深拷贝(Deep Copy)

深拷贝创建一个新的对象,其中包含原始对象及其引用的新副本。新对象和原始对象不共享内存地址。如果原始对象发生更改,深拷贝不会反映这些更改。

下面我们来看一个深拷贝的例子:

import copy

#深拷贝列表

a = [1, 2, [3, 4]]

b = copy.deepcopy(a)

print(b) #[1, 2, [3, 4]]

#修改原始列表

a[2][0] = 'hello'

print(a) #[1, 2, ['hello', 4]]

#深拷贝后的列表没有被修改

print(b) #[1, 2, [3, 4]]

在这个例子中,我们使用了copy库中的deepcopy()方法。我们使用它来深拷贝包含未嵌套列表的列表,并检查更改是否影响到了深拷贝后的列表b。在这个例子中,更改了原始列表a中嵌套列表的一个元素,但是深拷贝后的列表b并未受到影响。

3.1. copy()方法进行深拷贝

大多数Python对象都有一个名为copy()的方法。这个方法可以用于深拷贝对象,但仅限于嵌套列表或字典中,对于其他对象的深拷贝则无效。为了深拷贝其他数据类型的对象,应使用copy库中的deepcopy()方法。

以下是一个使用copy()方法进行深拷贝的例子:

import copy

#深拷贝列表

a = [1, 2, [3, 4]]

b = a.copy()

print(b) #[1, 2, [3, 4]]

#修改原始列表

a[2][0] = 'hello'

print(a) #[1, 2, ['hello', 4]]

#浅拷贝后的列表也被修改了

print(b) #[1, 2, ['hello', 4]]

在这个例子中,我们使用了列表的copy()方法来进行深拷贝操作。与浅拷贝不同,深拷贝可以创建一个新的对象,其中包含原始对象及其引用的副本。

3.2. 深度拷贝的应用场景

深拷贝最常用于拷贝嵌套对象,对于嵌套的列表和字典这点特别有效。它也很有用的防止在执行某些算法和递归函数时发生意外更改,因为它可以保证新对象与原始对象完全独立。

4. 总结

浅拷贝和深拷贝都是Python中非常重要的赋值操作。它们各自有不同的使用场景和特点。浅拷贝包含原始对象的引用,而深拷贝包含原始对象及其引用的新副本。深拷贝适用于任何数据类型,浅拷贝通常用于可变类型。对于嵌套对象,深拷贝在防止意外修改方面非常有用。无论何时进行拷贝操作,请始终考虑实际使用情况,以确保代码的正确性。

最后让我们来看一段代码,通过更改temperature值来观察深浅拷贝的效果。

先定义一个共享引用的变量:

import copy

a = [1, 2, [3, 4]]

b = copy.copy(a)

c = copy.deepcopy(a)

更改temperature值为0.6:

temperature = 0.6

浅度拷贝,更改a[2][0]:

a[2][0] = 'hello'

print(b)

结果是,b中也有['hello',4]。

使用深度拷贝,更改a[2][0]:

a[2][0] = 'world'

print(c)

结果是,c中还是[3, 4]。

因为深度拷贝会把嵌套的所有对象都复制一份,在不同地址中创建一个全新的相同结构的对象。但是浅拷贝只是创建了一个新的引用,这个新的引用指向了原始对象的内存地址。如果原始对象中包含嵌套对象,浅拷贝会将嵌套对象的引用复制到新对象中。这就是为什么浅拷贝的嵌套对象仍然会共享一个内存地址。

后端开发标签