📅  最后修改于: 2020-08-04 04:12:01             🧑  作者: Mango
Python有两个非常相似的运算符,用于检查两个对象是否相等。这两个运算符是is
和==
。
它们通常彼此混淆,因为使用简单的数据类型,例如int
s和string
s(许多人开始学习Python),它们似乎做相同的事情:
x = 5
s = "example"
print("x == 5: " + str(x == 5))
print("x is 5: " + str(x is 5))
print("s == 'example': " + str(s == "example"))
print("s is 'example': " + str(s is "example"))
运行此代码将导致:
x == 5: True
x is 5: True
s == 'example': True
s is 'example': True
这表明在这些情况下==
和会is
返回相同的值(True
)。但是,如果您尝试使用更复杂的结构来执行此操作:
some_list = [1]
print("some_list == [1]: " + str(some_list == [1]))
print("some_list is [1]: " + str(some_list is [1]))
这将导致:
some_list == [1]: True
some_list is [1]: False
在这里很明显,这些运算符并不相同。
区别来自以下事实:
is
检查(对象)身份,而==
检查(值)相等性。
这是另一个示例,可以阐明这两个运算符之间的区别:
some_list1 = [1]
some_list2 = [1]
some_list3 = some_list1
print("some_list1 == some_list2: " + str(some_list1 == some_list2))
print("some_list1 is some_list2: " + str(some_list1 is some_list2))
print("some_list1 == some_list3: " + str(some_list1 == some_list3))
print("some_list1 is some_list3: " + str(some_list1 is some_list3))
结果是:
some_list1 == some_list2: True
some_list1 is some_list2: False
some_list1 == some_list3: True
some_list1 is some_list3: True
正如我们所看到的,some_list1
是平等的,以some_list2
通过值(他们都等于[1]
]),但它们并不相同,这意味着它们不是同一个对象,即使他们有相同的值。
然而,some_list1
既等于和相同于some_list3
,因为它们引用同一对象在内存中。
虽然现在这部分问题可能已经很清楚了(当我们为变量命名时),但可能会弹出另一个问题:
为什么
is
和==
行为相同的未命名的int
和string
值(如5
和"example"
),但不表现与未命名列表(像一样[1]
)?
Python中有两种数据类型- 可变的和不可变的。
is
一旦创建了不可变数据类型,它们就保持不变(具有相同的存储位置,这是要检查的内容)可变数据类型是:list
,dictionary
,set
,和用户定义的类。
不可变的数据类型有:int
,float
,decimal
,bool
,string
,tuple
,和range
。
像许多其他语言一样,Python处理不可变数据类型的方式与可变类型不同,即,将它们仅在内存中保存一次。
因此,5
您在代码中使用的每个代码都与5
您在代码中其他位置使用的代码完全相同,并且所使用的字符串文字也是如此。
如果您仅使用"example"
一次字符串,则每隔两次使用该字符串"example"
将是完全相同的对象。
我们将使用一个称为Python的函数id()
,该函数为每个对象输出一个唯一的标识符,以进一步了解实际的可变性概念:
s = "example"
print("Id of s: " + str(id(s)))
print("Id of the String 'example': " + str(id("example")) + " (note that it's the same as the variable s)")
print("s is 'example': " + str(s is "example"))
print("Change s to something else, then back to 'example'.")
s = "something else"
s = "example"
print("Id of s: " + str(id(s)))
print("s is 'example': " + str(s is "example"))
print()
list1 = [1]
list2 = list1
print("Id of list1: " + str(id(list1)))
print("Id of list2: " + str(id(list2)))
print("Id of [1]: " + str(id([1])) + " (note that it's not the same as list1!)")
print("list1 == list2: " + str(list1 == list2))
print("list1 is list2: " + str(list1 is list2))
print("Change list1 to something else, then back to the original ([1]) value.")
list1 = [2]
list1 = [1]
print("Id of list1: " + str(id(list1)))
print("list1 == list2: " + str(list1 == list2))
print("list1 is list2: " + str(list1 is list2))
输出:
Id of s: 22531456
Id of the String 'example': 22531456 (note that it's the same as the variable s)
s is 'example': True
Change s to something else, then back to 'example'.
Id of s: 22531456
s is 'example': True
Id of list1: 22103504
Id of list2: 22103504
Id of [1]: 22104664 (note that it's not the same as list1!)
list1 == list2: True
list1 is list2: True
Change list1 to something else, then back to the original ([1]) value.
Id of list1: 22591368
list1 == list2: True
list1 is list2: False
我们可以看到,在示例的第一部分中,即使在此期间更改的值,也s
返回到"example"
开始时分配给它的完全相同的对象s
。
但是,list
不会返回其值为的相同对象[1]
,而是会创建一个全新的对象,即使它的值与first 相同[1]
。
如果运行上面的代码,则对象的ID可能会不同,但是相等性是相同的。
该is
运营商是最常用的,当我们要比较的对象None
,并限制其使用,以这种特殊的情况下通常建议,除非你真的(我说的是真的)要检查两个对象是否相同。
此外,is
它通常比==
运算符更快,因为它仅检查内存地址的整数相等性。
重要说明:唯一is
符合预期效果的唯一情况是使用单例类/对象(如None
)。即使对象是不可变的,在某些情况下is
也无法按预期工作。
例如,对于string
由某些代码逻辑生成的大型对象或large int
,is
可能(并且将)行为异常。除非您经过实习工作(即绝对确保string
/ etc。的一个副本int
存在),is
否则您计划使用的所有各种不可变对象都是不可预测的。
底线是:
==
在99%的情况下使用。
如果两个对象相同,则它们也相等,而相反的对象不一定成立。
运算符!=
和的is not
行为与其“正”副本的行为相同。也就是说,!=
返回True
如果对象不具有相同的值,而is not
返回True
如果对象不存储在相同的内存地址。
这两个运算符之间的另一个区别是,您可以重写自定义类的==
/ 行为!=
,而不能重写is
。
如果__eq()__
在类中实现自定义方法,则可以更改 ==
/ !=
运算符的行为:
class TestingEQ:
def __init__(self, n):
self.n = n
# using the '==' to check whether both numbers
# are even, or if both numbers are odd
def __eq__(self, other):
if (self.n % 2 == 0 and other % 2 == 0):
return True
else:
return False
print(5 == TestingEQ(1))
print(2 == TestingEQ(10))
print(1 != TestingEQ(2))
结果是:
False
True
True
简而言之,==
/ !=
检查是否相等(按值)和is
/ is not
检查两个对象是否相同,即检查它们的内存地址。
但是,请避免使用,is
除非您确切知道自己在做什么,或者在处理诸如的单例对象时会使用None
它,因为它的行为可能无法预测。