Python学习精粹014:比较两个对象(==与is)

文章讨论了Python中相等运算符(==)和身份运算符(is)的区别,重点在于对象的内存地址、值相等但地址不同的情况,以及小整数、字符串、列表、元组、字典和集合等数据类型的特殊处理方式。
摘要由CSDN通过智能技术生成

相等运算符(==)用来比较两个对象的内容(值)是否一致,身份运算符(is)用来比较两个对象的内存地址是否一致,即是否为同一对象。

来看下面的示例:

>>> a = 1

>>> b = 1

>>> id(a)

1678273568

>>> id(b)

1678273568

>>> a == b

True

>>> a is b

True

变量a、b都指向对象1,对象的值都相等,且对象的内存地址一致,所以a == b与a is b的运算结果都为True。

继续尝试:

>>> a = 256

>>> b = 256

>>> id(a)

1678281728

>>> id(b)

1678281728

>>> a = 257

>>> b = 257

>>> id(a)

50298224

>>> id(b)

50298768

>>> a == b

True

>>> a is b

False

奇怪的是,为何变量a、b指向对象256时,对象的内存地址相同,a == b与a is b的结果都为True,而当变量a、b指向对象257时,对象的内存地址不相同,a == b的结果为True,a is b的结果为False,为什么会出现这种现象呢?接下来看:

>>> a = -5

>>> b = -5

>>> id(a)

1678273376

>>> id(b)

1678273376

>>> a == b

True

>>> a is b

True

>>> c = -6

>>> d = -6

>>> id(c)

50298768

>>> id(d)

51007536

>>> c == d

True

>>> c is d

False

其中,让变量a、b指向对象-5,让变量c、d指向对象-6,仍出现了上述类似情况。

原因在于,考虑到小整数-5至257(不包含)会被频繁使用(如在for循环中的迭代次数),Python会在其启动后的运行时初始化过程中,一次性创建这些小整数对象,只会为它们分配一次内存,将它们缓存在小整数对象池(small_ints)之中,供共享使用,以提升整体性能,避免频繁分配和释放内存以及可能造成大量内存碎片。而在此范围之外的数字(如-6、257,以及浮点数),则会在每次对象创建时重新分配内存,所以内存地址也会不一样。例如:

>>> a = 1.0

>>> b = 1.0

>>> id(a)

3614160

>>> id(b)

3615336

类似于对小整数对象的处理,Python会对只包含英文字母、数字、下划线的字符串采取intern机制的处理,经过intern机制处理后的值相同的字符串对象,在Python解释器运行过程中只有唯一的一个,缓存至字符串缓冲池中,供共享使用,避免频繁创建和销毁字符串对象,提升执行效率。请看下面的示例:

>>> a = 'abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789' #@01 

 >>> b = 'abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789' #@02 

>>> id(a)

50328720

>>> id(b)

50328720

变量a、b都是指向同一个字符串对象(为同一内存地址),该字符串对象只包含了英文字母、数字、下划线(见#@01、#@02)。接着看:

>>> a = 'Hello World' #@01

>>> b = 'Hello World' #@02 

>>> id(a)

51069808

>>> id(b)

51070896

>>> a == b

True

>>> a is b

False

变量a、b所指向的字符串对象的值虽然相同,但由于包含了空格(见#@01、#@02),并非只是由英文字母、数字、下划线所组成,所以是两个不同的字符串对象。再看:

>>> a = '@' #@01 

>>> b = '@' #@02 

>>> id(a)

44265744

>>> id(b)

44265744

>>> c = '@1' #@03 

>>> d = '@1' #@04 

>>> id(c)

50973808

>>> id(d)

50973528

为何变量a、b指向的字符串对象@(见#@01、#@02,并非英文字母、数字或下划线)为同一内存地址,变量c、d指向的字符串对象@1(见#@03、#@04)则不是同一内存地址呢?

这是因为Python除了以intern机制处理和缓存以英文字母、数字、下划线组成的字符串,还会将长度为1的字符串对象缓存在专门的短字符串缓冲池(characters)之中,供共享使用。Python中内建的intern函数,可使值相同的字符串共用同一个字符串对象,避免为相同字符串重复分配内存空间,如下图所示:

接下来,我们再看看列表、元组、字典、集合使用相等运算符==与身份运算符is进行比较时的区别:

>>> # 对两个列表进行比较

>>> a = [1]

>>> b = [1]

>>> id(a)

50880840

>>> id(b)

50610888

>>> a == b

True

>>> a is b

False

为何变量a、b所指向的列表对象的值相同,却不是同一内存地址呢?这是因为列表为可变对象,Python会为每个列表分配内存。

>>> # 对两个元组进行比较

>>> a = (1)

>>> b = (1)

>>> id(a)

1451715616

>>> id(b)

1451715616

>>> a == b

True

>>> a is b

True

>>> c = (1, [1])

>>> d = (1, [1])

>>> id(c)

51154888

>>> id(d)

50417480

>>> c == d

True

>>> c is d

False

为何会出现上述结果?因为元组为不可变对象,当它只包含由不可变对象(如字符串)时,变量a、b所指向的对象相同,当它包含可变对象(如列表)时,变量c、d会指向不同的对象。

另外,再看看下面的代码:

>>> a = {1:'a'}

>>> b = {1:'a'}

>>> id(a)

50457408

>>> id(b)

51007424

>>> a == b

True

>>> a is b

False

>>> c = {1}

>>> d = {1}

>>> id(c)

50474568

>>> id(d)

50839112

>>> c == d

True

>>> c is d

False

可知,变量a、b指向的字典是可变对象,变量c、d指向的集合也是可变对象。

  • 17
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值