在 Python 中一切都是对象,毫无例外整数也是对象,对象之间比较是否相等能够用==
,也能够用is
。==
和is
操做的区别是:html
is
比较的是两个对象的id值是否相等,也就是比较俩对象是否为同一个实例对象,是否指向同一个内存地址。==
比较的是两个对象的内容是否相等,默认会调用对象的__eq__()
方法。清楚is
和==
的区别以后,对此也许你有可能会遇到下面的这些困惑,因而就有了这样一篇文章,试图把Python中一些隐晦的东西趴出来,但愿对你有必定的帮助。咱们先来看两段代码: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
>>>复制代码
片断二:spa
>>> a = 257
>>> b = 257
>>> a is b
False
>>>复制代码
对于257,a is b
返回的居然是False,结果可能在你的意料之中,也有可能出乎你的意料,但无论怎么,咱们仍是要刨根问底,找出问题的真相。.net
出于对性能的考虑,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
为了弄清楚这个问题,咱们有必要先理解程序代码块的概念。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]
获取的。
一番长篇大论以后,得出两点结论:一、小整数对象[-5,256]是全局解释器范围内被重复使用,永远不会被GC回收。二、同一个代码块中的不可变对象,只要值是相等的就不会重复建立新的对象。彷佛这些知识点对平常的工做一点忙也帮不上,由于你根本不会用is
来比较两个整数对象的值是否相等。那为何还要拿出来讨论呢?嗯,程序员学知识,不该该浅尝辄止,要充分发挥死磕到底的精神。
个人博客:foofish.net
扫一扫关注公众号获取最新文章: