之前的文章我们简单介绍了一下 Python 中异常处理,本篇文章我们来看一下 Python 中 is 和 == 的区别及深拷贝和浅拷贝。

我们先来看一下在 Python 中的双等号 == 。

== 是比较两个对象的内容是否相等,即两个对象的“值”是否相等,不管两者在内存中的引用地址是否一样。

is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。即is比较两个条件:1.内容相同。2.内存中地址相同

 a = 10000
b = 10000
print(a == b) # True
print(a is b) # True
print(id(a)) #
print(id(b)) # a = "hello world"
b = "hello world"
print(a == b) # True
print(a is b) # True
print(id(a)) #
print(id(b)) # a = [11,22,33]
b = [11,22,33]
print(a == b) # True
print(a is b) # False
print(id(a)) #
print(id(b)) #

在上面的代码中,我们分别定义了 a 和 b 两个变量,通过输出结果可以发现当变量为字符串或数字时, is 和 == 的输出结果是一样的,当为列表时 is 和 == 结果不一样,通过打印两个变量的 id 值可以看出两个 id 值不一样,这是由于当我们创建列表 a 和 b 时,是分别开辟了两块内存来分别存储这两个变量,从表象上来看结果是一样的,但两个变量所指向的内存地址不一样,我们将上面的代码改为如下:

 a = [11,22,33]
b = a
print(a == b) # True
print(a is b) # True
print(id(a)) #
print(id(b)) #

在上面的代码中,我们并没有直接给变量 b 赋值,而是让 b=a,这样的话 b 和 a 就指向了同一块内存,所以 a is b 就为 True 了。

上面的代码我是在 PyCharm 编辑器中实现的,但是在终端命令行实现的话结果却是不一样的,如下:

 >>> a = 10000
>>> b = 10000
>>> a == b
True
>>> a is b
False
>>> id(a)
4360555120
>>> id(b)
4360555216

当我们将 a 和 b 的值变小时,如下:

 >>> a = 100
>>> b = 100
>>> a == b
True
>>> a is b
True
>>> id(a)
4357367984
>>> id(b)
4357367984

造成上面的原因是因为python对小整数在内存中直接创建了一份,不会回收,所有创建的小整数变量直接从对象池中引用他即可。但是注意Python仅仅对比较小的整数对象进行缓存(范围为范围[-5, 256])缓存起来,而并非是所有整数对象。也就说只有在这个[-5,256]范围内创建的变量值使用is比较时候才会成立。

在 PyCharm 中,当值超过 256 时 is 和 == 的输出结果仍是一样,这是因为解释器也做了一部分优化,对于数字和字符串这类变量都进行了缓存。

我们再来看一下在终端命令行中当变量为字符串时:

 >>> a = "hello world"
>>> b = "hello world"
>>> a == b
True
>>> a is b
False
>>> id(a)
4359747248
>>> id(b)
4361247408
 >>> a = "hello"
>>> b = "hello"
>>> a == b
True
>>> a is b
True
>>> id(a)
4361199040
>>> id(b)
4361199040

通过输出结果可以看出,在命令行中当变量为简单字符串时输出结果一致,否则输出结果不一致,这是由于 Python 对简单字符串对象也进行了缓存,这样做的意义是可以优化代码的运行速度,减少内存消耗。

在上面的代码中,我们让 a=b 其实是一种浅拷贝的过程,他们指向的是同一块内存,当我们改变其中一个变量时,另一个也会变,如下:

 a = [11,22,33]
b = a
a[0] = 123
print(a) # [123, 22, 33]
print(b) # [123, 22, 33]

在 Python 中还有深拷贝,它是重新开辟一块区域用来存储变量的,如下:

 import copy

 a = [11, 22, 33]
b = a
c = [11, 22, 33]
d = copy.deepcopy(a)
print(a == b, a is b) # True True
print(a == c, a is c) # True False
print(a == d, a is d) # True False a[0] = 123
print(a) # [123, 22, 33]
print(b) # [123, 22, 33]
print(c) # [11, 22, 33]
print(d) # [11, 22, 33]

在上面的代码中我们引入了一个 copy 的模块,引入模块这个之前的文章没有提到,后续会单独说一下。

在 copy 模块中有一个 deepcopy() 的方法,从上面的代码中可以看出 deepcopy() 的方法就相当于 c=[11,22,33] 这样重新开辟一块区域来存储变量,当 a 变量改变时,浅拷贝的内容 b 会随之改变,但是深拷贝的内容 d 并不是指向 a 的内存地址,所以不会改变。

在 copy 的模块中还有一个 copy() 方法,它在某些方面看起来和 deepcopy() 方法是一样的,其实不一样,如下:

import copy

a = [11, 22, 33]
b = copy.copy(a)
c = copy.deepcopy(a)
a[0] = 123
print(a) # [123, 22, 33]
print(b) # [11, 22, 33]
print(c) # [11, 22, 33]

从上面的输出结果看,当 a 变量修改之后,b 变量和 c 变量一样没有改变,那 copy() 和 deepcopy() 到底有什么区别呢,我们再看下面的代码:

 import copy

 a = [11, 22, [123,456]]
b = copy.copy(a)
c = copy.deepcopy(a)
a[2][0] = 789
print(a) # [11, 22, [789, 456]]
print(b) # [11, 22, [789, 456]]
print(c) # [11, 22, [123, 456]]

从上面的输出结果可以看出,b 变量随 a 变量的变化而变化了,而 c 变量没有。

很显然这时 copy() 函数拷贝的值随着原对象的值修改了,而 deepcopy() 的值没有随着原对象的值修改。主要是因为 deepcopy()  会将复杂对象的每一层复制一个单独的个体出来对于 copy() 函数要慎用,慎用。

Python 从入门到进阶之路(七)的更多相关文章

  1. Python 从入门到进阶之路(一)

    人生苦短,我用 Python. Python 无疑是目前最火的语言之一,在这里就不再夸他的 NB 之处了,本着对计算机编程的浓厚兴趣,便开始了对 Python 的自学之路,并记录下此学习记录的心酸历程 ...

  2. Python 从入门到进阶之路(六)

    之前的文章我们简单介绍了一下 Python 的面向对象,本篇文章我们来看一下 Python 中异常处理. 我们在写程序时,有可能会出现程序报错,但是我们想绕过这个错误执行操作.即使我们的程序写的没问题 ...

  3. Python 从入门到进阶之路(五)

    之前的文章我们简单介绍了一下 Python 的函数,本篇文章我们来看一下 Python 中的面向对象. Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是 ...

  4. Python 从入门到进阶之路(四)

    之前的文章我们简单介绍了一下 Python 的几种变量类型,本篇文章我们来看一下 Python 中的函数. 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性, ...

  5. Python 从入门到进阶之路(三)

    在之前的文章我们介绍了一下 Python 中 if while for 的使用,本章我们来看一下 Python 中的变量类型. 在 Python 定义变量时的规则是 变量名 = 变量 ,Python ...

  6. Python 从入门到进阶之路(二)

    之前的文章我们对 Python 语法有了一个简单的认识,接下来我们对 Python 中的 if while for 做一下介绍. 上图为 if 判断语句的流程,无论任何语言,都会涉及到判断问题,if ...

  7. python快速入门及进阶

    python快速入门及进阶 by 小强

  8. Python 爬虫从入门到进阶之路(七)

    在之前的文章中我们一直用到的库是 urllib.request,该库已经包含了平常我们使用的大多数功能,但是它的 API 使用起来让人感觉不太好,而 Requests 自称 “HTTP for Hum ...

  9. Python 爬虫从入门到进阶之路(六)

    在之前的文章中我们介绍了一下 opener 应用中的 ProxyHandler 处理器(代理设置),本篇文章我们再来看一下 opener 中的 Cookie 的使用. Cookie 是指某些网站服务器 ...

随机推荐

  1. servlet的三大作用域对象和jsp的九大内置对象及其四大作用域对象

    servlet的三大作用域对象: request(HttpServletRequest) session(HttpSession): application(ServletContext):tomca ...

  2. nyoj 737 石子合并(区间DP)

    737-石子合并(一) 内存限制:64MB 时间限制:1000ms 特判: No通过数:28 提交数:35 难度:3 题目描述:     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为 ...

  3. java8-date和timeAPI

    一 我们为什么要学习 java.timeAPI 原先的Date and Calendar 类的api比较复杂,不易于理解,应用起来不是很灵活. Calendar 是个线程不安全的类会导致SimpleD ...

  4. css3 伪类实现右箭头→

    css3 实现右箭头→ <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  5. Java之缓冲流(字节/字符缓冲流)

    概述 缓冲流,也叫高效流,是对4个基本的 FileXxx 流的增强,所以也是4个流,按照数据类型分类: 字节缓冲流: BufferedInputStream , BufferedOutputStrea ...

  6. Leetcode题解 - DFS部分简单题目代码+思路(113、114、116、117、1020、494、576、688)

    这次接触到记忆化DFS,不过还需要多加练习 113. 路径总和 II - (根到叶子结点相关信息记录) """ 思路: 本题 = 根到叶子结点的路径记录 + 根到叶子结点 ...

  7. Python真牛逼,获取压缩文件密码,我只要一分钟!

    事情的经过是这样的: 又是奶茶,行吧行吧. 快点开工,争取李大伟回来之前搞定. 李大伟说是6位数字密码 那么我们可以利用python生成全部的六位数字密码 这样,我们就生成了一个从000000到999 ...

  8. Python-xlwt库的基本使用

    安装xlwt库 pip install xlwt 基本使用 ①创建工作簿 wa = xlwt.Workbook() ②添加工作表 添加“class”工作表 b = wa.add_sheet('clas ...

  9. Audit Object Changes 审核对象更改

    Important 重要 The Audit Trail module is not supported by the Entity Framework ORM in the current vers ...

  10. 前端面试题套路--终极版(Vue、JavaScript)

    前言 面试题是永远都准备不完的!!!!! 前端常见的一些问题 1.前端性能优化手段? 1. 尽可能使用雪碧图 2. 使用字体图标代替图片 3. 对HTML,css,js 文件进行压缩 4. 模块按需加 ...