Python List的赋值方法 深拷贝与浅拷贝

本文详细介绍了Python中对象复制的不同方式,包括赋值、浅拷贝和深拷贝的区别与应用场景。通过实例展示了每种复制方式的特点及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >




  Python中关于对象复制有三种类型的使用方式,赋值、浅拷贝与深拷贝。他们既有区别又有联系,刚好最近碰到这一类的问题,研究下。

一、赋值

        在python中,对象的赋值就是简单的对象引用,这点和C++不同。如下:        

[python] view plain copy
print ?
  1. a = [1,2,3,“hello”,[“python”,“C++”]]  
  2. b = a  
  3. print a==b #True  
a = [1,2,3,"hello",["python","C++"]]
b = a
print a==b #True
        这种情况下,b和a是一样的,他们指向同一片内存,b不过是a的别名,是引用。我们可以使用a与b是否相同来判断,返回True,表明他们地址相同,内容相同。

        赋值操作(包括对象作为参数、返回值)不会开辟新的内存空间,它只是复制了新对象的引用。也就是说,除了b这个名字以外,没有其它的内存开销。

        修改了a,就影响了b;同理,修改了b就影响了a。

[python] view plain copy
print ?
  1. a = [1,2,3,“hello”,[“python”,“C++”]]  
  2. b = a  
  3. b.append(”ADD”)  
  4. print “a=”,a,“b=”,b   
a = [1,2,3,"hello",["python","C++"]]
b = a
b.append("ADD")
print "a=",a,"b=",b 
[python] view plain copy
print ?
  1. #a=[1, 2, 3, ‘hello’, [‘python’, ‘C++’], ‘ADD’] b=[1, 2, 3, ‘hello’, [‘python’, ‘C++’], ‘ADD’]  
#a=[1, 2, 3, 'hello', ['python', 'C++'], 'ADD'] b=[1, 2, 3, 'hello', ['python', 'C++'], 'ADD']

二、浅拷贝(shallow copy)

        浅拷贝会创建新对象,其内容是原对象的引用

        浅拷贝有三种形式:切片操作,工厂函数,copy模块中的copy函数。比如对上述a:        

        1、切片操作:b = a[:]   或者 b = [each for each in a]

        2、工厂函数:b = list(a)

        3、copy函数:b = copy.copy(a)

        浅拷贝产生的b不再是a了,使用is可以发现他们不是同一个对象,使用id查看,发现它们也不指向同一片内存。但是当我们使用 id(x) for x in a 和 id(x) for x in b 时,可以看到二者包含的元素的地址是相同的。

        在这种情况下,a和b是不同的对象,修改b理论上不会影响a。比如b.append([4,5])。

[python] view plain copy
print ?
  1. a = [1,2,3,“hello”,[“python”,“C++”]]  
  2. b = a[:]  
  3. b.append(”ADD”)  
  4. print “a”,a,“b”,b  
a = [1,2,3,"hello",["python","C++"]]
b = a[:]
b.append("ADD")
print "a",a,"b",b
#a [1, 2, 3, ‘hello’, [‘python’, ‘C++’]] b [1, 2, 3, ‘hello’, [‘python’, ‘C++’], ‘ADD’]

        但是要注意,浅拷贝之所以称为浅拷贝,是它仅仅只拷贝了一层,在a中有一个嵌套的list,如果我们修改了它,情况就不一样了。

        a[4].append(“C”)。查看b,你将发现b也发生了变化。这是因为,你修改了嵌套的list。修改外层元素,会修改它的引用,让它们指向别的位置,修改嵌套列表中的元素,列表的地址并为发生变化,指向的都是同一个位置。

三、深拷贝(deep copy)

        深拷贝只有一种形式,copy模块中的deepcopy函数。

        和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。因而,它的时间和空间开销要高。

        同样对la,若使用b = copy.deepcopy(a),再修改b将不会影响到a了。即使嵌套的列表具有更深的层次,也不会产生任何影响,因为深拷贝出来的对象根本就是一个全新的对象,不再与原来的对象有任何关联。

四、关于拷贝操作的警告

        1、对于非容器类型,如数字,字符,以及其它“原子”类型,没有拷贝一说。产生的都是原对象的引用。

        2、如果元组变量值包含原子类型对象,即使采用了深拷贝,也只能得到浅拷贝。

        </div>
            </div>

        </article>
<think>好的,我现在要回答用户关于Python赋值深拷贝还是浅拷贝的问题。首先,我需要确认自己对这两个概念的理解是否正确。浅拷贝(Shallow Copy)会创建一个新对象,然后插入原对象中元素的引用。也就是说,如果原对象中的元素是可变的,修改这些元素会影响拷贝后的对象。而深拷贝(Deep Copy)则是完全复制原对象及其所有子对象,生成一个完全独立的新对象,两者互不影响。 接下来,用户的问题是关于Python中的赋值操作属于哪一种。根据我的知识,普通的赋值操作(如使用等号=)实际上并不会创建新对象,而只是将变量名指向同一个对象。这时候,变量名相当于原对象的一个别名,两者指向同一块内存地址。因此,无论是可变对象(如列表、字典)还是不可变对象(如整数、字符串),通过赋值操作后的变量修改都会影响到原变量。例如,当a是一个列表,执行b = a后,修改b的元素也会同时修改a的元素,因为它们指向同一个列表。 不过,用户可能混淆了赋值拷贝的概念。在Python中,赋值不是拷贝操作,既不深也不浅。拷贝需要使用特定的方法,比如列表的copy方法浅拷贝)、copy模块的copy函数(浅拷贝)和deepcopy函数(深拷贝)。因此,回答时需要明确区分赋值和拷贝的不同,并举例说明不同情况下的行为。 接下来,我需要考虑用户可能的疑问点。例如,用户可能认为赋值后修改新变量不会影响原变量,但实际上会,尤其是对于可变对象。因此,需要举例说明这一点,并指出不可变对象的情况(如元组、字符串)在修改时会创建新对象,而不会影响原变量,但这拷贝无关,而是因为不可变对象本身的特性。 然后,我需要组织回答的结构,确保逻辑清晰。首先明确回答赋值不是拷贝,而是引用同一个对象。然后解释浅拷贝深拷贝的区别,并说明如何通过不同方法实现这两种拷贝。最后,通过示例代码展示不同操作的结果,帮助用户理解。 同时,需要注意使用中文术语的准确性,比如“引用”、“可变对象”、“不可变对象”等。还要确保示例代码的正确性,比如使用列表的浅拷贝深拷贝后的修改情况,展示它们对原对象的影响差异。 可能还需要提醒用户,在处理嵌套结构或包含其他可变对象的对象时,深拷贝的重要性。例如,一个列表中包含另一个列表,浅拷贝只会复制外层列表的引用,内层列表仍然共享,而深拷贝会递归复制所有层级的对象,确保完全独立。 最后,总结关键点,强调赋值拷贝的区别,以及在不同情况下选择适当的拷贝方式,避免因共享引用导致意外的副作用。</think>在Python中,**直接赋值既不是深拷贝也不是浅拷贝**,而是创建了原对象的引用(别名)。具体行为取决于操作方式,以下是详细说明: --- ### 一、直接赋值的本质 ```python a = [1, 2, [3]] b = a # 直接赋值 ``` - **内存关系**:$b$和$a$指向同一个内存对象 - **修改影响**: ```python b.append(4) print(a) # 输出 [1, 2, [3], 4](同步变化) ``` --- ### 二、浅拷贝 vs 深拷贝 | 操作 | 方法 | 特点 | 嵌套结构影响 | |---------------------|-------------------------------|--------------------------------------|-----------------------------| | **浅拷贝** | `copy.copy()` 或 `list.copy()` | 只复制顶层对象,子对象保持引用 | 修改嵌套元素会互相影响 | | **深拷贝** | `copy.deepcopy()` | 递归复制所有层级对象 | 完全独立,无相互影响 | --- ### 三、示例对比 #### 1. 浅拷贝示例 ```python import copy original = [1, [2, 3]] shallow = copy.copy(original) # 修改顶层元素 shallow[0] = 100 print(original) # 输出 [1, [2, 3]](无影响) # 修改嵌套元素 shallow[1].append(4) print(original) # 输出 [1, [2, 3, 4]](同步变化) ``` #### 2. 深拷贝示例 ```python import copy original = [1, [2, 3]] deep = copy.deepcopy(original) # 修改任何层级元素 deep[1].append(4) print(original) # 保持 [1, [2, 3]](完全独立) ``` --- ### 四、可视化对比 ``` 原始对象 浅拷贝对象 深拷贝对象 ┌───┬───┐ ┌───┬───┐ ┌───┬───┐ │ 1 │ ●─┼─────▶│ 1 │ ●─┼─────┐ │ 1 │ ●───┐ └───┴─┬─┘ └───┴─┬─┘ │ └───┴─┬─┘ │ ▼ ▼ │ ▼ │ ┌───┬───┐ ┌───┬───┐ │ ┌───┬───┐ │2 │ 3 │ │2 │ 3 │◀─┘ │2 │ 3 │ └───┴───┘ └───┴───┘ └───┴───┘ ``` --- ### 五、核心结论 1. **赋值操作**:创建引用(所有修改同步) 2. **浅拷贝**:适合单层结构(嵌套部分仍共享) 3. **深拷贝**:适合多层嵌套结构(完全独立) 通过合理选择拷贝方式,可以避免因对象共享引用导致的意外修改问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值