📌  相关文章
📜  Python中的’is’与’==’-对象比较

📅  最后修改于: 2020-08-04 04:12:01             🧑  作者: Mango

Python中的’is’vs’==’

Python有两个非常相似的运算符,用于检查两个对象是否相等。这两个运算符是is==

它们通常彼此混淆,因为使用简单的数据类型,例如ints和strings(许多人开始学习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==行为相同的未命名的intstring值(如5"example"),但不表现与未命名列表(像一样[1])?

Python中有两种数据类型- 可变的不可变的

  • 可变数据类型是您可以随时间“更改”的数据类型
  • is一旦创建了不可变数据类型,它们就保持不变(具有相同的存储位置,这是要检查的内容)

可变数据类型是:listdictionaryset,和用户定义的类。

不可变的数据类型有:intfloatdecimalboolstringtuple,和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’和’==’?

is运营商是最常用的,当我们要比较的对象None,并限制其使用,以这种特殊的情况下通常建议,除非你真的(我说的是真的)要检查两个对象是否相同。

此外,is它通常比==运算符更快,因为它仅检查内存地址的整数相等性。

重要说明:唯一is符合预期效果的唯一情况是使用单例类/对象(如None)。即使对象是不可变的,在某些情况下is无法按预期工作。

例如,对于string由某些代码逻辑生成的大型对象或large intis可能(并且将)行为异常。除非您经过实习工作(即绝对确保stringetc。的一个副本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

结论

简而言之,==!=检查是否相等(按值)和isis not检查两个对象是否相同,即检查它们的内存地址。

但是,请避免使用,is除非您确切知道自己在做什么,或者在处理诸如的单例对象时会使用None它,因为它的行为可能无法预测。