在 Python 中一切都是对象,毫无例外整数也是对象,对象之间比较是否相等可以用==,也可以用is。==和is操作的区别是:

is比较的是两个对象的id值是否相等,也就是比较俩对象是否为同一个实例对象,是否指向同一个内存地址。 ==比较的是两个对象的内容是否相等,默认会调用对象的__eq__()方法。

清楚is和==的区别之后,对此也许你有可能会遇到下面的这些困惑,于是就有了这样一篇文章,试图把Python中一些隐晦的东西趴出来,希望对你有一定的帮助。我们先来看两段代码:

片段一:

>>> a = 256  >>> b = 256  >>> a == b  True  >>>

片段二:

>>> a = 256  >>> b = 256  >>> a is b  True  >>>

在交互式命令行执行上面两段代码,代码片段一中的a==b返回True很好理解,因为两个对象的值都是256,对于片段二,a is b也返回True,这说明a和b是指向同一个对象的,可以检查一下他们的id值是否相等:

>>> id(a)  8213296  >>> id(b)  8213296  >>>

结果证明他俩的确是同一个对象,指向的是同一个内存地址。那是不是所有的整数对象只要两个对象的值(内容)相等,它们就是同一个实例对象呢?换句话说,对于整数对象只要==返回True,is操作也会返回True吗?带着这个问题来看下面这两段代码:

片段一:

>>> a = 257  >>> b = 257  >>> a == b  True  >>>

片段二:

>>> a = 257  >>> b = 257  >>> a is b  False  >>yszx11.cn >

对于257,a is b返回的竟然是False,结果可能在你的意料之中,也有可能出乎你的意料,但不管怎么,我们还是要刨根问底,找出问题的真相。

解惑一

出于对性能的考虑,Python内部做了很多的优化工作,对于整数对象,Python把一些频繁使用的整数对象缓存起来,保存到一个叫small_ints的链表中,在Python的整个生命周期内,任何需要引用这些整数对象的地方,都不再重新创建新的对象,而是直接引用缓存中的对象。Python把这些可能频繁使用的整数对象规定在范围[-5, 256]之间的小对象放在small_ints中,但凡是需要用些小整数时,就从这里面取,不再去临时创建新的对象。因为257不再小整数范围内,因此尽管a和b的值是一样,但是他们在Python内部却是以两个独立的对象存在的,各自为政,互不干涉。

弄明白第一个问题后,我们继续在Python交互式命令行中写一个函数,再来看下面这段代码:

片段一:

>>> c = 257  >>> def foo():  ... a = 257  ... b = 257  ... print a is b  ... print a is c  ...  >>> foo()  True  False

呃,什么情况,是的,你没看错,片段一中的这段代码 a、b 值都是257的情况下,出现了a is b返回True,而a is c 返回的False,a、b、c的值都为257,为什么会出现不同的结果呢?这对于刚刚好不容易建立起来的认知就被彻底否决了吗,那这段代码中究竟发生了什么?难道解惑一中的结论是错误的吗?

解惑二

A Python program is constructed from code blocks. A block is a piece of Python program text that is executed as a unit. The following are blocks: a module, a function body, and a class definition. Each command typed interactively is a block. A script file (a file given as standard input to the interpreter or specified as a command line argument to the interpreter) is a code block. A script command (a command specified on the interpreter command line with the ‘-c‘ option) is a code block. structure-of-a-program zhengshu5.com

为了弄清楚这个问题,我们有必要先理解程序代码块的概念。Python程序由代码块构成,代码块作为程序的一个最小基本单位来执行。一个模块文件、一个函数体、一个类、交互式命令中的单行代码都叫做一个代码块。在上面这段代码中,由两个代码块构成,c = 257作为一个代码块,函数foo作为另外一个代码块。Python内部为了将性能进一步的提高,凡是在一个代码块中创建的整数对象,如果存在一个值与其相同的对象于该代码块中了,那么就直接引用,否则创建一个新的对象出来。Python出于对性能的考虑,但凡是不可变对象,在同一个代码块中的对象,只有是值相同的对象,就不会重复创建,而是直接引用已经存在的对象。因此,不仅是整数对象,还有字符串对象也遵循同样的原则。所以 a is b就理所当然的返回True了,而c和a不在同一个代码块中,因此在Python内部创建了两个值都是257的对象。为了验证刚刚的结论,我们可以借用dis模块从字节码的角度来看看这段代码。

>>> import dis  >>> dis.dis(foo)    2           0 LOAD_CONST               1 (257)                3 STORE_FAST               0 (a)       3           6 LOAD_CONST               1 (257)                9 STORE_FAST               1 (b)       4          12 LOAD_FAST                0 (a)               15 LOAD_FAST                1 (b)               18 COMPARE_OP               8 (is)               21 PRINT_ITEM                         22 PRINT_NEWLINE             5          23 LOAD_FAST                0 (a)               26 LOAD_GLOBAL              0 (c)               29 COMPARE_OP               8 (is)               32 PRINT_ITEM                         33 PRINT_NEWLINE                     34 LOAD_CONST               0 (None)               37 RETURN_VALUE

可以看出两个257都是从常量池的同一个位置co_consts[1]获取的。

总结

一番长篇大论之后,得出两点结论:1、小整数对象[-5,256]是全局解释器范围内被重复使用,永远不会被GC回收。2、同一个代码块中的不可变对象,只要值是相等的就不会重复创建新的对象。似乎这些知识点对日常的工作一点忙也帮不上,因为你根本不会用is来比较两个整数对象的值是否相等。那为什么还要拿出来讨论呢?嗯,程序员学知识,不应该浅尝辄止,要充分发挥死磕到底的精神。

Python解惑:整数比较的更多相关文章

  1. Python中整数和浮点数

    Python支持对整数和浮点数直接进行四则混合运算,运算规则和数学上的四则运算规则完全一致. 基本的运算: 1 + 2 + 3 # ==> 6 4 * 5 - 6 # ==> 14 7.5 ...

  2. Python源代码--整数对象(PyIntObject)的内存池

    [背景] 原文链接:http://blog.csdn.net/ordeder/article/details/25343633 Python整数对象是不可变对象,什么意思呢?比如运行例如以下pytho ...

  3. python将整数均分成N等分

    在python中,需要将整数均分成N等分.python divide integers N equal parts sum # 拆分整数 def split_integer(m, n): assert ...

  4. python 小整数池 和intern 【整理】

    小整数对象池 (在python内置了) 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间. Python对小整数的定义是[-5,257]这些整 ...

  5. Python中小整数对象池和大整数对象池

    1. 小整数对象池 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间. Python 对小整数的定义是 [-5, 256] 这些整数对象是提 ...

  6. Python之整数,浮点数和布尔类型

    整数和浮点数有那个四则运算: 两种类型的数可以直接进行加减,当整数和浮点数进行加减的时候,结果会自动的变为浮点数,其中除法运算是“/”来表示的, 而余数的算术符号是“%”来表示的.如果是为了求除完后的 ...

  7. Python 的整数与 Numpy 的数据溢出

    某位 A 同学发了我一张截图,问为何结果中出现了负数? 看了图,我第一感觉就是数据溢出了.数据超出能表示的最大值,就会出现奇奇怪怪的结果. 然后,他继续发了张图,内容是 print(100000*20 ...

  8. python中小整数对象池及intern机制

    小整数对象池: Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁 Python 对小整数的定义是 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收,所有位于这个范围 ...

  9. [Python源码剖析]获取Python小整数集合范围

    #!/usr/bin/env python #-*- coding=utf-8 -*- small_ints = dict() for i in range(-10000,10000): small_ ...

随机推荐

  1. Luogu3793 由乃救爷爷 分块、ST表

    传送门 因为昨天写暴力写挂在UOJ上用快排惨遭卡常,所以今天准备写一个卡常题消遣消遣,然后时间又垫底了QAQ 这道题显然需要支持一个\(O(N)\)预处理\(O(1)\)查询的ST表,显然普通的ST表 ...

  2. 字符串阵列String[]转换为整型阵列Int[]

    原始数据: string input = "3,7,2,8,1,9,1,34,67,78,22"; 要处理为: " }; 最终处理为: , , , , , , , , , ...

  3. C# 定时器和队列结合,卖包子啦,Timer、 AutoResetEvent、 ManualResetEvent

    再你们得到源码之前,我先做个广告:张家港杰德机械/张家港三兴华轩机械是我一朋友的公司,希望需要做净水,灌装机,拔盖机,封口机,传送带等的朋友光顾. 张家港杰德机械有限公司:http://www.jie ...

  4. NOIp2014提高组初赛错题简析

    总体分析 \(89pts\),粗略来看选择题错的比较多,\(-6pts\).同时又是尿性的填空杀扣了\(5pts\). 不过后面的两大题全对了还是可喜可贺 错题精析 单项选择T8 编译器的主要功能是( ...

  5. 校内模拟赛 SovietPower Play With Amstar

    SovietPower Play With Amstar 题意: 一棵二叉树,每次询问一条路径上的路径和,初始每个点有一个权值1,询问后权值变为0.$n \leq 10^7,m\leq10^6$ 分析 ...

  6. python第二周

    第二周,PYTHON图形绘制 一,计算机技术的演进发展 1946-1981.从第一台计算机的诞生到IBM的PC机的出现,我们称之为”计算机系统结构时代“.————这个时代重点在解决计算能力问题 198 ...

  7. C#_委托的使用

    C#基础---委托的使用   一:什么是委托     委托是一种定义方法签名的类型当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联.您可以通过委托实例调用方法.委托是一个引用类型,所以它具 ...

  8. 四则运算coding

    https://coding.net/u/ztf1641429293/p/sizeyunshuan/git/blob/master/Sizenyunsuan.java

  9. LINUX内核分析第八周总结:进程的切换和系统的一般执行过程

    一.进程调度与进程切换 1.不同的进程有不同的调度需求 第一种分类: I/O密集型(I/O-bound) 频繁的进行I/O 通常会花费很多时间等待I/O操作的完成 CPU密集型(CPU-bound) ...

  10. java-过滤器、拦截器

    1.基础知识 1.1面向对象编程(OOP).面向切面编程(AOP) 面向对象编程: 将需求功能划分为不同的.相对独立的和封装良好的类,使他们有属于自己的行为,依靠继承和多态等来定义彼此的关系. 面向切 ...