Anders Wang


我所认识的每个人都是榜样,都有值得我去尊敬和学习的地方。


理解Python中is 与 == 的区别

在Python中,有一个问题会被经常问到,那就是运算符is==有什么区别?

很多人都知道他们都是比较两个对象是否相等,说起来都是比较对象,但是分不清什么时候用哪个,其实非常容易区分只要记住一点。

==是比较运算符,它比较的是两个对象中的值是否是相等的。而is是同一性运算符,比较的是两个对象的id值是否相等或者说比较的是对象的内存空间地址是否相等。

为了更好更深刻的理解,我们还是从几个例子出发:

a = 1, 2, 3  
b = 1, 2, 3  
print(f'The result of (a == b) is: {a == b}')  
print(f'The result of (a is b) is: {a is b}')

# 输出如下:
# The result of (a == b) is: True
# The result of (a is b) is: False

我们可以发现,a和b的值都是一个值为1, 2, 3的元组类型。所以在用比较运算符==比较时显示为True

但是用is同一性运算符比较时,结果却为False,因为尽管它们的值是相等的,但是这两个对象各自的内存空间地址是不相等的。我们可以向下面这样用Python内置的id()函数来查看独享的内存地址信息。

print(f'a: {id(a)}, b: {id(b)}')

# 输出如下:
# a: 112163566792, b: 112166450376

可以发现,2个对象的内存地址不一样,所以用is比较的时候结果为False

现在,我们创建了一个新对象c,然后把a赋值给c,也就是说a和c两个变量指向的是同一个对象地址,当我们用id()函数查看内存地址时显示地址的确一样,所以再次用is运算符比较的时候显示为True,而且反过来推如果is比较下来相等,那么用==比较自然也相等。

c = a  
print(f'The result of (a is c) is: {a is c}')  
print(f'a: {id(a)}, c: {id(c)}')

# 输出内容:
# The result of (a is c) is: True
# a: 112163566792, c: 112163566792

这里必须要提一下,还有一个看似很奇怪的比较问题也经常被拿来反问一些新手。

在Python里明明新创建一个变量对象就会开辟一个内存空间,那么用is比较的时候应该是不同的地址,返回应该是False,可是下面为什么他们返回True而且内存地址是相同的呢?

s1 = 'hello'  
s2 = 'hello'

print(f's1: {id(s1)}, s2: {id(s2)}')  
print(f'The result of (s1 is s2) is: {s1 is s2}')

# 输出内容:
# s1: 112167134296, s2: 112167134296
# The result of (s1 is s2) is: True

而如果赋值的是长一点的字符串时,可以看到确实得到了正常该有的结果(确实创建了两个不同对象,用is判断确实应该返回False)。

s3 = 'hello, Anders'  
s4 = 'hello, Anders'

print(f's3: {id(s3)}, s4: {id(s4)}')  
print(f'The result of (s3 is s4) is: {s3 is s4}')

# 输出内容:
# s3: 112166728944, s4: 112167126384
# The result of (s3 is s4) is: False

这是因为前一种情况下Python的字符串驻留机制起了作用。对于较小的字符串或者整数,为了提高系统性能Python会保留其值的一个副本,当创建新的字符串的时候直接指向该副本即可。所以 "hello" 在内存中只有一个副本,s1 和 s2 的 id 值相同,而 "hello, Anders" 是长字符串,不驻留内存,Python中各自创建了两个对象s2 和 s4,所以他们的值相同但 id 值不同。

那么,看看下面这个奇怪的例子。前面我们解释到了,对于较小的字符串或者整数,为了提高系统性能Python会保留其值的一个副本,也就不会创建新的内存空间了,所以你会看到如下示例给变量a1,b1赋值为256时,实际上他们是一个内存空间地址,自然is比较下来为True,可是为什么当给a2,b2按一样的方式赋值整数只是赋的值为257结果却为False呢?

a1 = 256  
b1 = 256  
print(f'The result of (a1 is b1) is: {a1 is b1}')

a2 = 257  
b2 = 257  
print(f'The result of (a2 is b2) is: {a2 is b2}')

# 输出如下:
# The result of (a1 is b1) is: True
# The result of (a2 is b2) is: False

因为,整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。

Python 对小整数的定义是 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,无论这个整数处于LEGB中的哪个位置,所有位于这个范围内的整数使用的都是同一个对象。同理,单个字母也是这样的。

最近的文章

Python常用高阶函数

高阶函数是在Python中一个非常有用的功能函数,所谓高阶函数就是一个函数可以用来接收另一个函数作为参数,这样的函数叫做高阶函数。 为了便于理解,我们从实际例子来看看函数当做参数被传递到另个函数是什么…

Python, 技术博文详细阅读
更早的文章

numpy.where的用法

在用Python处理大量数据时,Python的数据科学库极为有用,这里要提到的就是Numpy库。在Numpy库里有个where函数,它是Python中三元表达式 x if condition else…

Python, 技术博文详细阅读
comments powered by Disqus