身份运算符
大家好!在这一章,我们来讲解一下 Python 中的身份运算符。你可能会遇到这种情况:有两个变量,它们的值相同,但我们需要判断它们是否指向同一个对象。
简介
Python 中的身份运算符用来判断两个对象的引用是否为同一个,换言之,就是用来比较两个对象的内存地址是否相同。

身份运算符用于判断两个对象的引用是否是同一个,换句话说,它用来比较两个对象的内存地址是否一致。举个例子,假设我们有两个变量,它们存储的是同一个对象,还是说它们存储的是两个相同值但不同对象,这就需要用到身份运算符来判断了。
Python 对数字和字符串做了一些优化以提高性能和减少内存开销。以下是 Python 对数字和字符串做的一些优化:
-
整数池(Integer Pool):Python 会在程序运行时预先创建一些整数对象,并将其保存在整数池中。这样,在创建整数对象时,可以重用已存在的对象,而不是创建新的对象。这在一定程度上减少了内存开销。
-
字符串池(String Pool):对于较短的字符串,Python 会使用字符串池进行优化。字符串池是一个缓存区,保存着所有共享相同内容的字符串对象。当创建新的字符串对象时,Python 会首先检查是否已经存在相同内容的字符串对象,如果存在,则直接重用已有的对象,避免重复创建新的对象。
值得注意的是,Python 对一些常见的类型做了优化,尤其是数字和字符串。比如,Python 会在程序运行时为常见的整数和短字符串创建池,并重用这些对象,避免重复创建。
因此,在某些情况下,字面量相同的两个对象,实际并不是同一个对象,此时如果需要区分对象的话,就需要使用身份运算符。
这就是为什么有时即使两个变量值相同,它们的内存地址可能仍然不一样。理解这一点对于正确使用身份运算符非常重要。
身份运算符如下表所示:
| 运算符 | 描述 |
|---|---|
is |
is 是判断两个标识符是不是引用自一个对象 |
is not |
is not 是判断两个标识符是不是引用自不同对象 |
Python 提供了身份运算符 is 和 is not 来帮助我们进行这种判断。接下来,我们就来看看这两个运算符如何工作,并结合一些例子来理解它们的应用。
身份运算符 is
is 用来判断两个对象内存引用地址是否相同,如果相同,结果为真 True,如果不相同,结果为假 False
# 示例 1
str1 = "Hello"
str2 = "Hello"
print(id(str1)) # 输出第一个字符串对象的内存地址
print(id(str2)) # 输出第二个字符串对象的内存地址
print(str1 == str2)
print(str1 is str2)
# 示例 2
str3 = "Hello, World!" * 1000
str4 = "Hello, World!" * 1000
print(id(str3)) # 输出第一个字符串对象的内存地址
print(id(str4)) # 输出第二个字符串对象的内存地址
print(str3 == str4)
print(str3 is str4)
我们先来看 is 运算符。它用来判断两个对象的内存地址是否相同。如果它们是同一个对象,返回 True,否则返回 False。我们通过几个例子来看看如何使用。在第一个示例中,str1 和 str2 都是字符串 "Hello",它们的值相同,但它们是否引用同一个对象呢?通过 id 我们可以看到它们的内存地址。通常,Python 会复用小的字符串,所以它们可能会指向同一个内存地址。而在第二个示例中,虽然 str3 和 str4 的值完全相同,它们是由同一长字符串重复拼接而成,但由于字符串池的优化,它们可能是两个不同的对象,内存地址不同。
注意:两个字面量相同的对象,内存地址未必相同,就像两个双胞胎,长的相同,但是是两个独立的个体。
这里大家需要注意一下,两个字面量相同的对象,内存地址未必相同,就像两个双胞胎,长得相同,但是是两个独立的个体。
身份运算符 is not
is not 用来判断两个对象内存引用地址是否不同,如果不同,结果为真 True,如果相同,结果为假 False
# 示例 1
str1 = "Hello"
str2 = "Hello"
print(id(str1)) # 输出第一个字符串对象的内存地址
print(id(str2)) # 输出第二个字符串对象的内存地址
print(str1 == str2)
print(str1 is not str2)
# 示例 2
str3 = "Hello, World!" * 1000
str4 = "Hello, World!" * 1000
print(id(str3)) # 输出第一个字符串对象的内存地址
print(id(str4)) # 输出第二个字符串对象的内存地址
print(str3 == str4)
print(str3 is not str4)
接下来,我们来看 is not 运算符。它用于判断两个对象的内存地址是否不同。如果它们是不同的对象,返回 True,如果它们是同一个对象,返回 False。让我们通过以下示例来进一步理解。在这里,is not 用来判断 str1 和 str2 是否不是同一个对象。如果它们的内存地址不同,返回 True,否则返回 False。
is 和 == 的区别
在 Python 中,万物皆对象,而对象的三个基本要素:
- 内存地址
- 数据类型
- 值
在 Python 中,所有的变量本质上都是对象。而每个对象都有三个基本属性:内存地址、数据类型和它的值。上面的例子中我们使用了 is 和两个等号这两个运算符。下面我们来总结一下这两个运算符之间有什么区别。
而 is 与 == 都作为常用的判断语句去进行使用,这两者之间的主要区别是:
==运算符: 只比较两个对象的值,相同返回True,不同返回False。is运算符: 比较两个对象的地址引用,相同返回True,不同返回False。
等于等于运算符比较的是两个对象的值是否相同。如果值相同,返回 True,否则返回 False。is 运算符比较的是两个对象的内存地址是否相同。如果它们指向的是同一个对象,返回 True,否则返回 False。
在这种场景下, 两个判断的执行结果均为 True。
a, b = 1,1
# 判断a,b 是否相等
print(a == b)
print(a is b)
在这个例子中,结果为 True,因为 Python 对整数有优化,1 会复用相同的内存地址。
在这种场景下, 两个判断的执行结果不一致。
a = [1,2,3]
b = [1,2,3]
# 对比值一致,返回True
print(a == b)
# 对比内存地址不一致,返回False
print(a is b)
但是对于列表对象 a 和 b,它们虽然值相等,但是 is 返回的是 False,因为它们在内存中的位置不同。
总结
- 成员运算符 in
- 成员运算符 not in
最后我们来总结一下。这个章节中我们学习了 Python 中的身份运算符 is 和 is not。is 用来判断两个对象是否是同一个对象,即它们是否有相同的内存地址;is not 则用于判断两个对象是否不是同一个对象。需要注意的是,is 和等于等于的区别:等于等于比较的是对象的值,而 is 比较的是对象的内存地址。在实际编程中,理解这两者的差异非常重要,帮助我们避免不必要的错误。