我的图片 · 在线免费的图片处理工具

前言

先看这三行:

a = [1]; b = [1]
print(a == b, a is b, a[0] is b[0])

跑出来:

True False True

其实整道题就绕着生活里一个特别简单的区别打转 —— 长得一样,和是同一个东西,是两码事。双胞胎长得一样,但不是同一个人。== 问「你俩长得一样吗」,is 问「你俩根本就是同一个吗」。

Python 里数字、列表、元组在这件事上表现不太一样,容易混。所以下面按这三样分开看:先看整数 ,再看装它的列表,最后换成元组。

正文

整数

Python 3.15 把这份「提前造好的整数名单」扩大了:从 -5~256 改成 -5~1024。

Python一启动时就把预定的整数进行缓存,上面有写范围。之后谁要用 ,发的都是那一份:

x = 1
y = 1
print(x is y, x == y)

输出:

True True

数字又不会变,大家一起用一份没任何问题。

is 比的是每样东西自带的编号,id() 能看到:

print(id(x) == id(y))

输出:

True

id() 打出来是一长串数字,而且每次运行都不一样,别去记它,看两个编号「相不相等」就够了。

但别拿 is 比数字

刚才那个 True,只是 Python 顺手做的省事优化,不是规矩。换个数字立刻翻车:

x = 1024
y = int("1024")
print(x == y, x is y)

输出:

#Python 3.15之前
True False

#Python 3.15之后
True Ture

再来一个

x = 1025
y = int("1025")
print(x == y, x is y)

输出:

True False

那 is 留着干嘛

日常几乎只剩一个用处:判断 None。

x = None
print(x is None)

输出:

True

None 整个程序里就一份,问「是不是同一个」最干脆。写 x == None 多数时候也能跑,但「什么叫相等」是可以被别人改的,is 改不了,所以大家都写 is None。True 和 False 也各只有一份,不过平时直接写 if flag: 更顺手。

列表

写两次 [1],Python 就老老实实造两个新列表 —— 像你把同一份购物清单抄了两遍,纸是两张,内容一模一样:

a = [1]; b = [1]
print(a == b, a is b, a[0] is b[0])

输出:

True False True

== 逐项比内容,所以是 True;两张纸当然不是同一张,所以 is 是 False。那第三项为什么又 True 了?因为列表里装的不是 1 本身,是「指到 1 的箭头」,两张纸上的箭头都指到上一节那个共用的 1。

列表不能像整数那样共用,原因也很直白:列表能改,两个人共用一份会互相捣乱。想让两个名字指着同一张纸,得直接 b = a:

a = [1]
b = a
b.append(2)
print(a, b, a is b)

输出:

[1, 2] [1, 2] True

a 也跟着变了,因为它俩压根就是同一个列表。只想复制内容的话用 copy():

a = [1]
c = a.copy()
c.append(2)
print(a, c, a is c)

输出:

[1] [1, 2] False

说白了就一句:能改的东西各造各的,不能改的东西可以共用。

元组

把列表换成元组,答案基本没变:

a = tuple([1, 2])
b = tuple([1, 2])
print(a == b, a is b, a[0] is b[0])

输出:

True False True

元组只是「自己改不了」,Python 并没有规定内容一样的元组必须共用一份,所以这儿照样是两个元组、里面共用一个 1。

不过元组比列表多几个小意外。

一、字面量写法可能被偷偷合并

a = (1, 2)
b = (1, 2)
print(a is b)

写在同一个 .py 文件里跑,CPython 常见输出:

True

编译器发现两次写的是一模一样的常量,就只造一份,两个名字都指过去。但在交互式里一行行敲(每行单独编译),通常又是 False:

>>> a = (1, 2)
>>> b = (1, 2)
>>> a is b
False

空元组更彻底,整个程序里就一份:

print(() is ())

输出:

True

这些都是 Python 自己省事的做法,不是规矩。

二、元组里装的东西决定第三项

装小整数时,元素还是共用的那份;换成列表,就各造各的了:

t1 = ([1],)
t2 = ([1],)
print(t1 == t2, t1 is t2, t1[0] is t2[0])

输出:

True False False

顺带破一个常见误会:「元组不可变」说的是元组里装的那些箭头不能换,不是里面的东西不能动:

t = ([1],)
t[0].append(2)
print(t)

输出:

([1, 2],)

t[0] = 其它 会报错,但 t[0].append(2) 没问题。正因为里面可能装着能改的列表,Python 也不能随便把两个元组合并成一份。

还有一点,类型不一样就不相等:

print((1, 2) == [1, 2])

输出:

False

内容看着一样,但一个是元组一个是列表,== 不认。

小结

  1. == 问是否相等(你俩长得一样吗?)
  2. is 问是否是同一个(你俩根本就是同一个吗)

参考文章

  • AI
  • Python 文档

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

none
暂无评论...