一. 赋值运算

l1 = [1, 2, 'conan', [11, 22]]
l2 = l1 l1[0] = 111
print(l1) # [111, 2, 'conan', [11, 22]]
print(l2) # [111, 2, 'conan', [11, 22]]
print(id(l1[0])) # 1872924208
print(id(l2[0])) # 1872924208 l1.append(333)
print(l1) # [111, 2, 'conan', [11, 22], 333]
print(l2) # [111, 2, 'conan', [11, 22], 333]
print(id(l1)) # 2211423993544
print(id(l2)) # 2211423993544 l1[3].append(666)
print(l1) # [111, 2, 'conan', [11, 22, 666], 333]
print(l2) # [111, 2, 'conan', [11, 22, 666], 333]
print(id(l1[3])) # 2211453800136
print(id(l2[3])) # 2211453800136

​ 从上面的运行结果可以看到, 对于赋值运算来说, l1与l2指向的是同一个内存地址, 所以它们是完全一样的. 其中一个变量对列表进行改变, 剩下的变量在使用列表时, 就是使用的改变之后的列表.

二. 浅copy

# 同一代码块下
l1 = [1, 2, 'conan', [11, 22]]
l2 = l1.copy() l1[0] = 111
print(l1) # [111, 2, 'conan', [11, 22]]
print(l2) # [1, 2, 'conan', [11, 22]]
print(id(l1[0])) # 1872924208
print(id(l2[0])) # 1872920688 print(id(l1[1])) # 1872920720
print(id(l2[1])) # 1872920720 l1.append(333)
print(l1) # [111, 2, 'conan', [11, 22], 333]
print(l2) # [1, 2, 'conan', [11, 22]]
print(id(l1)) # 2343138115272
print(id(l2)) # 2343138954824 l1[3].append(666)
print(l1) # [111, 2, 'conan', [11, 22, 666], 333]
print(l2) # [1, 2, 'conan', [11, 22, 666]]
print(id(l1[3])) # 2343138954952
print(id(l2[3])) # 2343138954952
# 不同代码块下
l1 = [1, 2, 'conan', [11, 22]]
l2 = l1.copy() l1[0] = 111
print(l1) # [111, 2, 'conan', [11, 22]]
print(l2) # [1, 2, 'conan', [11, 22]]
print(id(l1[0])) # 1872924208
print(id(l2[0])) # 1872920688 print(id(l1[1])) # 1872920720
print(id(l2[1])) # 1872920720 l1.append(333)
print(l1) # [111, 2, 'conan', [11, 22], 333]
print(l2) # [1, 2, 'conan', [11, 22]]
print(id(l1)) # 2402040017736
print(id(l2)) # 2402040018120 l1[3].append(666)
print(l1) # [111, 2, 'conan', [11, 22, 666], 333]
print(l2) # [1, 2, 'conan', [11, 22, 666]]
print(id(l1[3])) # 2402040003848
print(id(l2[3])) # 2402040003848

对于浅copy来说, 只是在内存中重新开辟了一个空间存放一个新列表, 但是新列表里面的元素与原列表里面的元素的内存地址是同一个. 所以, l1与l2的id不同, 但是里面内容的id是相同的.

注意

我们发现, 在更改l1的第一个元素, 也就是把 1 改为 111 之后, 内存地址是不一样的, 这是因为int类型是不可变的数据类型; 而列表时可变的数据类型, 当里面的列表增加一个元素后, 其内存地址是不变的.

三. 深copy

依旧是先看下代码

import copy
l1 = [1, 2, 'conan', [11, 22]]
l2 = copy.deepcopy(l1) l1[0] = 111
print(l1) # [111, 2, 'conan', [11, 22]]
print(l2) # [1, 2, 'conan', [11, 22]]
print(id(l1[0])) # 1872924208
print(id(l2[0])) # 1872920688 print(id(l1[1])) # 1872920720
print(id(l2[1])) # 1872920720 l1.append(333)
print(l1) # [111, 2, 'conan', [11, 22], 333]
print(l2) # [1, 2, 'conan', [11, 22]]
print(id(l1)) # 2698658605000
print(id(l2)) # 2698660016776 l1[3].append(666)
print(l1) # [111, 2, 'conan', [11, 22, 666], 333]
print(l2) # [1, 2, 'conan', [11, 22]]
print(id(l1[3])) # 2698659950152
print(id(l2[3])) # 2698660016712

对于深copy来说, 深copy后的列表是在内存中重新创建的. 而且Python为了节省内存以及提高性能, 它做了这么一件事:

在深copy后的列表中,

如果其元素是可变的数据类型就再重新创建一个;

如果其元素是不可变的数据类型, 就公用一个, 也就是其内存地址是一样的.

在上面代码中的运行结果也能看出来.

四. 总结

浅copy: 嵌套的可变的数据类型 是 同一个.

深copy: 嵌套的可变的数据类型 不是 同一个.

五. 练习

5.1 练习1

写出下面代码的运行结果

l1 = [1, 2, 3, ['conan']]
l2 = l1[::]
l1[-1].append(666)
print(l1)
print(l2)

l1: [1, 2, 3, ['conan', 666]]

l2: [1, 2, 3, ['conan', 666]]

通过打印其id可以发现, l2 = l1[::] 的操作其实与浅copy一样.

『Python基础』第20节:深浅copy的更多相关文章

  1. 『Python基础』第2节: Python简介及入门

    一. Python介绍 Python是一门高级计算机程序设计语言,1989年,荷兰的Guido von Rossum创造了它.Guido是是一个牛人,1982年,他从阿姆斯特丹大学获得了数学和计算机硕 ...

  2. 『Python基础』第4节:基础数据类型初识

    本节只是对基础数据类型做个简单介绍, 详情会在之后慢慢介绍 什么是数据类型? 我们人类可以分清数字与字符串的区别, 可是计算机不能. 虽然计算机很强大, 但在某种程度上又很傻, 除非你明确告诉它数字与 ...

  3. 『Python基础』第7节:基本运算符

    一. 基本运算符 运算按种类可以分为: 算数运算.比较运算.逻辑运算.赋值运算.成员运算.身份运算.位运算. 今天我们只学习算数运算.比较运算.逻辑运算.赋值运算.成员运算 1.1 算数运算 以下假设 ...

  4. 『Python基础』第5节:条件控制

    if 语句的使用 单分支 if 条件: 满足条件后要执行的代码 例如: if 2 < 3: print(222) print(333) 每个条件后面都要使用冒号 :, 表示接下来是满足条件后要执 ...

  5. 『Python基础』第39节 函数的返回值

    1. 函数的返回值 ​ 一个函数就是封装一个功能, 这个功能一般都会有一个最终结果的. ​ 比如写一个登录的函数, 最终登录是否成功你总得告诉我一声吧? ​ 还有咱们之前也用过 len() 这个函数, ...

  6. 『Python基础』第8节:格式化输出

    现在有一个需求, 询问用户的姓名, 年龄, 工作, 爱好, 然后打印成以下格式 ************ info of Conan ************ name: Conan age: 23 ...

  7. 『Python基础』第6节:流程控制之while循环

    在生活中经常遇到循环的事情, 比如循环列表播放歌曲等. 在Python中, 也有循环, 就是其流程控制语句while. 1. 基本循环 while 条件: 循环体 # 如果条件为真, 那么就执行循环体 ...

  8. 『Python基础』第1节 Windows环境下安装Python3.x

    一. Python安装 1. 下载安装包 https://www.python.org/downloads/release/python-374/ # 3.7安装包 # 如需安装python2.7版本 ...

  9. 『Go基础』第8节 格式化输出

    输出就是将数据信息打印到电脑屏幕上. 本节我们就来学习一下Go语言中的三种输出方式: Print().Println().Printf(). 1.Print() Print()主要的一个特点就是打印数 ...

随机推荐

  1. ssh端口映射总结

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/boliang319/article/det ...

  2. Linux内核TCP MSS机制详细分析

    前言 上周Linux内核修复了4个CVE漏洞[1],其中的CVE-2019-11477感觉是一个很厉害的Dos漏洞,不过因为有其他事打断,所以进展的速度比较慢,这期间网上已经有相关的分析文章了.[2] ...

  3. WebSocket——SuperWebSocket实现服务端和客户端

    WebSocket——SuperWebSocket实现服务端和客户端具体实现如下: 注:本作者是基于vs2019 enterprise版本,所有项目均为.Net Framwork4.7版本(因为Web ...

  4. 枚举(Enum)

    enum是一个全新的“类”. 枚举(Enum): 我们所定义的每个枚举类型都继承自java.lang.Enum类.枚举中的每个成员都是public static final的. 当您使用“enum”定 ...

  5. VsCode写Python代码!这代码简直和大神一样规范!太漂亮了!

    VsCode写Python代码!这代码简直和大神一样规范!太漂亮了!    转 https://www.jianshu.com/p/636306763d89 VsCode虽然没有Pycharm的功能齐 ...

  6. ES6深入浅出-13 Proxy 与 Reflect-1.Reflect 反射

    阮一峰  http://es6.ruanyifeng.com/#docs/reflect MDN有一些简陋的介绍 https://developer.mozilla.org/zh-CN/docs/We ...

  7. [译]在Pandas的Dataframe中删除行、列

    导入模块 import pandas as pd 创建dataframe data = {'name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy'], 'yea ...

  8. 使用Commons math做数值计算

    使用Commons math做数值计算 觉得有用的话,欢迎一起讨论相互学习~Follow Me 最近使用jmetal做多目标的时候,想用一些简单的方法求最大值最小值方差和协方差矩阵,但是原生代码真的是 ...

  9. 【k8s secret token 删掉自动重建】kubernetes secret 和 serviceaccount

    https://stackoverflow.com/questions/54354243/kubernetes-secret-is-persisting-through-deletes

  10. [转]Ubuntu 上创建常用磁盘阵列

    链接地址:https://www.jianshu.com/p/9a458510593a