本文同时发表在Prodesire公众号和Prodesire博客。简介Python的“is”和“==”想必大家都不陌生。我们在比较变量和字面量的时候经常会用到它们,那么它们有什么区别呢?你什么时候应该使用is?我什么时候应该使用==?这已经成为很多人心中的一个困惑。当我们判断一个变量是否为None时,我们通常使用is:>>>a=None>>>aisNoneTrue>>>b=1>>>bisNoneFalse而当我们判断一个变量是否为字面量时(对于例如,某个值),通常==:>>>a=0>>>a==0True>>>a==1False要解决上面的疑惑,我们首先要了解is和==是什么。什么是“是”和“==”?is用于检查身份(identity),即两个变量是否指向同一个对象。==用于检查值是否相等(equality),即两个变量的值是否相等。Identity标识也意味着值相等,因为两者都指向同一个对象,所以值必须相等。但反之则不然。__eq__魔术方法由于==用于检查值的相等性,那么两个对象的值比较究竟是如何进行的呢?我们很容易理解基本类型对象的值比较。比如列表对象[1,2,3]的值比较就是比较列表的长度和列表中每个元素的值。但是对于自定义对象,如何比较值呢?这就涉及到了__eq__(self,other)这个魔术方法,通过它我们可以实现对象的==逻辑。例如:>>>classFoo(object):...def__eq__(self,other):...returnTrue...>>>foo=Foo()>>>foo==1True>>>foo==NoneTrue>>>fooisNoneFalse在上面的例子中,我们定义了Foo类并实现了__eq__(self,other)方法,它总是返回True,这意味着它与任何对象比较(==)的结果都是都是真的。而当它进行身份比较时,比如与None比较时,它会返回False,因为它不是同一个对象。场景示例示例1:变量指向同一个对象的比较>>>a=[1,2,3]>>>b=a#b指向a,a指向[1,2,3],所以b指向同一个[1,2,3]>>>bisaTrue>>>b==aTrue在上面的例子中,a和b都指向同一个列表对象[1,2,3],所以使用is和==在他们身上,结果都是True。示例2:比较指向不同对象(但值相同)的变量>>>a=[1,2,3]>>>b=a[:]#b复制a指向的列表生成一个新的[1,2,3]>>>bisaFalse>>>b==aTrue在上面的例子中,由于b指向了a的副本,也就是说a和b指向了两个不同的对象,所以对于他们使用的结果是False。但是由于值是相等的,所以使用==的结果是True。例3:变量指向字面量的比较>>>a=256>>>b=256#和a指向同一个字面量256>>>aisb#表示同一个对象True>>>a==bTrue>>>>>>a=257>>>b=257>>>a==bTrue>>>aisb#表示指向不同的对象False>>>一般来说,两个变量都指向字面量,他们的比较应该be使用==而不是is,否则你可能会像上面的例子一样混淆。在Python的交互式解释器中,可能经常使用的整数对象被指定在[-5,256]范围内,它们在创建时会被缓存。但是每当需要再次使用它们时,它们将从缓存中获取而不是重新创建对象。当a和b都引用同一个字面值256时,aisb返回True。这是因为当声明b=256时,256整数对象是从缓存中取出的,而不是重新创建的,所以a和b指向同一个整数对象.aisb当a和b都引用同一个字面量257时返回False。这是因为当声明b=257时,257整数对象没有被缓存而是重新创建,所以a和b指向不同的整数对象。同样,如果字面量是字符串,结果也类似。>>>a='python.org'>>>b='python.org'>>>a是bFalse>>>a==bTrue>>>a='pythonorg'>>>b='pythonorg'>>>aisbTrue>>>a==bTruePython3.8在比较字面量和is时引入SyntaxWarning鉴于使用is比较字面量实际上是不正确的,在Python3.8的发行说明中,引入了以下内容:当身份检查(是和不是)与某些类型的文字(例如字符串、数字)一起使用时,编译器现在会生成SyntaxWarning。这些在CPython中经常会意外工作,但语言规范不保证。该警告建议用户改为使用相等性测试(==和!=)。(由SerhiyStorchaka在bpo-34850中贡献。)因此,当我们使用is来比较数字和字符串等文字时,会报SyntaxWarning:>>>x=200>>>xis200Traceback(mostrecentcalllast):文件“
