Python 中 is 和 == 的区别

目录

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 的编译机制代码块字符缓冲池等。

这里不做赘述,会重新拆分出一篇文章进行整理。后续会将文章链接贴在这里。

对于这一部分,我参考了几篇文章,感觉写得挺好,可以参考下:

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十甫寸木南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值