目录
- Python 中对象的三要素(Id, Type, Value)
is
VS==
is
的几种特殊情况Python 编译机制
| 代码块 |小整数对象池
和字符串intern机制
(仅说明,具体内容见另一篇文章)- 参考资料
Python 中对象的三要素(Id, Type, Value)
-
Id: 唯一标识一个对象
-
Type: 标识对象的类型
-
Value: 对象的值
>>> my_string = "I am a string" >>> id(my_string) 4498919600 >>> type(my_string) <class 'str'> >>> my_string 'I am a string'
is
VS ==
-
is
在 Python 中叫做身份运算符或同一性运算符,比较判断的是对象间的唯一身份标识,即比较的是对象的 Id,也就是在比较两个对象在内存中的位置是否相同。 -
==
是标准的比较运算符,用于比较判断两个对象的 Value 是否相等,默认会调用对象的__eq__()
方法。>>> a = "I am a string" >>> b = a >>> c = "I am a string" >>> a is b True >>> a is c False >>> a == b True >>> a == c True >>> id(a) 4311719856 >>> id(b) 4311719856 >>> id(c) 4311765936
is
的几种特殊情况
is 比较判断的是不同对象的 Id 是否相等
这一标准在比较大多数类型的对象时都是适用的,但是在比较 int 和 str 时会有些不同之处。
>>> a = (1, 2, 3) # a 和 b 为 tuple 类型
>>> b = (1, 2, 3)
>>> a is b
False
>>> id(a)
4357441024
>>> id(b)
4357526592
>>>
>>> a = [1, 2, 3] # a 和 b 为 list 类型
>>> b = [1, 2, 3]
>>> a is b
False
>>> id(a)
4357525632
>>> id(b)
4357525760
>>>
>>> a = {
1: 10, 2: 20, 3: 30} # a 和 b 为 dict 类型
>>> b = {
1: 10, 2: 20, 3: 30}
>>> a is b
False
>>> id(a)
4357133376
>>> id(b)
4357133440
>>>
>>> a = set([1, 2, 3]) # a 和 b 为 set 类型
>>> b = set([1, 2, 3])
>>> a is b
False
>>> id(a)
4357494592
>>> id(b)
4357495040
>>>
>>> a = 1 # a 和 b 为 int 类型
>>> b = 1
>>> a is b
True
>>> id(a)
4354664896
>>> id(b)
4354664896
>>>
>>> a = "string" # a 和 b 为 str 类型
>>> b = "string"
>>> a is b
True
>>> id(a)
4357527088
>>> id(b)
4357527088
可以很明显地看到在比较 int 和 str 时,虽然分别定义了两个对象 a 和 b,但是,用 is 比较这两个对象的结果却是 True!
这是怎么回事?
这与 is 的定义相悖啊!
但是与此同时,我们也可以注意到,在比较 int 和 str 时,分别定义的两个对象 a 和 b 的 Id 是一样的!
- 原来,为了优化速度,避免为整数频繁申请和销毁内存空间,在 Python 中有这样一个机制:
对于在 [-5, 257) 区间内的整数,Python 会在程序启动时创建一个小整数池,将它们全部保存到一个叫
small_ints
的链表中,这个整数池会伴随着 Python 程序的整个生命周期,不会回收。之后,如果要创建在 [-5, 257) 区间内的整数,Python 会直接引用整数池中对应的对象。因此,对于 [-5, 257) 区间内的整数,只要它们的值相等,那么它们的引用地址就都相等,即 Id 相等。
该机制在 Python 中叫做“小整数对象池”。
>>> a = -5 >>> b = -5 >>> a is b True >>> id(a) 4391184640 >>> id(b) 4391184640 >>> a = 256 >>> b = 256 >>> a is b True >>> id(a) 4391192992 >>> id(b) 4391192992 >>> a = -6 >>> b = -6 >>> a is b False >>> id(a) 4393924016 >>> id(b) 4393923984 >>> a = 257 >>> b = 257 >>> a is b False >>> id(a) 4393924048 >>> id(b) 4393924016
-
而对于 str 来说,Python 中同样有一个类似的机制:
在 Python 中,字符串对象是不可变对象。
Python 会维护一个字典,这个字典维护已经创建的符合维护机制的字符串(key)和该字符串对象的地址(value)。
每次创建字符串对象时都会和该字典进行比较,如果该字符串符合维护机制(只包含[0-9a-zA-Z_])并且已经在字典中存在,那么新创建的字符串就直接引用该已存在的字符串,否则就创建并由该字典进行维护。
这个机制叫做“
intern
机制(String intern
| 字符串驻留)”。>>> a = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_" >>> b = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_" >>> a is b True >>> id(a) 4394047056 >>> id(b) 4394047056 >>> a = "I am a string" >>> b = "I am a string" >>> a is b False >>> id(a) 4394044592 >>> id(b) 4394044656 >>> a = "^_^" >>> b = "^_^" >>> a is b False >>> id(a) 4394044720 >>> id(b) 4394044592
-
值得注意的是:
小整数对象池
是在运行程序之前就由 Python 创建好的intern 机制(String intern | 字符串驻留)
中的字典是在程序运行中创建并不断添加的
Python 编译机制
| 代码块 | 小整数对象池
和字符串intern机制
对于 int 和 str 来说,虽然有小整数对象池
和字符串intern机制
来确保对一些常用的变量进行缓存。但这并不是 int 和 str 的全部,在 Python 中,还有其他的机制会对 int 和 str 的创建造成影响。
如:Python 的编译机制
、代码块
、字符缓冲池
等。
这里不做赘述,会重新拆分出一篇文章进行整理。后续会将文章链接贴在这里。
对于这一部分,我参考了几篇文章,感觉写得挺好,可以参考下:
参考资料
- ==和之间的区别在Python中,is (这篇文章是最浅显的理解,并不正确,可以做一个反面案例)
- Python中is和==的区别
- python小特性:is和==、变量的内存管理、小整数对象池、intern机制
- python tips:小整数对象池与字符串intern
- Python基础:is和==的区别