在Python中,万物皆对象,整数无一例外都是对象。可以使用==或者is来比较对象是否相等。==和is操作的区别在于:is比较两个对象的id值是否相等,即比较两个对象是否是同一个实例对象,是否指向同一个内存地址。==比较的是两个对象的内容是否相等,默认会调用对象的__eq__()方法。了解了is和==的区别之后,你可能会遇到下面的困惑,所以就有了这样一篇文章,试图揭示Python中一些晦涩难懂的东西,希望对你有所帮助。我们先看两段代码:段1:>>>a=256>>>b=256>>>a==bTrue>>>段2:>>>a=256>>>b=256>>>aisbTrue>>>在交互式命令行执行上面两段代码。很容易理解代码片段1中的a==b返回True,因为两个对象的值都是256。对于片段2,aisb也返回True,也就是说a和b指向同一个对象,可以查看它们的id值是否相等:>>>id(a)8213296>>>id(b)8213296>>>事实证明,它们确实是同一个指向同一个内存地址的对象.只要两个对象的值(内容)相等,所有整数对象都是同一个实例对象吗?换句话说,只要==对整型对象返回True,那么is操作也会返回True吗?有了这个问题是看下面两段代码:Fragment1:>>>a=257>>>b=257>>>a==bTrue>>>Fragment2:>>>a=257>>>b=257>>>aisbFalse>>>对于257,aisb返回False。结果不一定如你所愿,但无论如何,我们还是要追根究底,找出问题的真相。困惑1.出于性能的考虑,Python内部做了很多优化工作。对于整型对象,Python会缓存一些经常使用的整型对象,保存在一个名为small_ints的链表中。在Python的整个生命周期中,任何需要引用这些整型对象的地方都不会再新建对象,而是直接引用缓存中的对象。Python把这些经常使用的[-5,256]范围内的整数对象放到small_ints中,但是每当你需要用到一些小整数的时候,你可以从这里取,而不是临时创建新的对象。因为257已经不在小整数范围内了,即使a和b的值相同,但是在Python内部作为两个独立的对象存在,相互独立,互不干扰。弄清楚第一个问题后,我们继续在Python交互式命令行中写一个函数,然后看下面的代码:Fragment1:>>>c=257>>>deffoo():...a=257...b=257...printaisb...printaisc...>>>foo()TrueFalse额,什么情况?对于257,aisb返回True,aisc返回False。a、b、c的值都是257,为什么会有不同的结果呢?是不是完全被拒绝了,那么这段代码到底发生了什么?谜题1中的结论是否错误?谜题2Python程序是由代码块构成的。块是作为一个单元执行的一段Python程序文本。以下是块:模块、函数体和类定义。交互键入的每个命令都是一个块。脚本文件(作为解释器的标准输入或指定为解释器的命令行参数的文件)是一个代码块。脚本命令(在解释器命令行上使用“-c”选项指定的命令)是一个代码块。structure-of-a-program为了弄清楚这个问题,我们有必要先了解程序代码块的概念。Python程序由代码块组成,代码块作为程序的最小基本单元执行。模块文件、函数体、类或交互式命令中的单行代码称为代码块。在上面的代码中,它由两个代码块组成,c=257作为一个代码块,functionfoo作为另一个代码块。为了进一步提高Python内部的性能,对于在一个代码块中创建的任何整型对象,如果代码块中存在具有相同值的对象,那么将直接引用它,否则将创建一个新对象。Python出于性能考虑,所有不可变对象,同一个代码块中的对象,只要对象具有相同的值,就不会重复创建,而是直接引用已经存在的对象。所以不仅是整数对象,字符串对象也遵循同样的原则。所以aisb理所当然地返回True,而c和a不在同一个代码块中,所以在Python内部创建了两个值为257的对象。为了验证刚才的结论,我们可以借用dis模块,从字节码的角度来看这段代码。>>>importdis>>>dis.dis(foo)20LOAD_CONST1(257)3STORE_FAST0(a)36LOAD_CONST1(257)9STORE_FAST1(b)412LOAD_FAST0(a)15LOAD_FAST1(b)18COMPARE_OP8(is)21PRINT_ITEM28PRINT_NEWLINE523LOAD_FAST0(aG)26BAST0(aG)2BAST0(is)32PRINT_ITEM33PRINT_NEWLINE34LOAD_CONST0(None)37RETURN_VALUE可以看出,这两个257都是从常量池中同一个位置co_consts[1]得到的。总结了一个长篇大论,得出两个结论:1、小整数对象[-5,256]在全局解释器范围内被重用,永远不会被GC回收。2.对于同一个代码块中的不可变对象,只要取值相等,就不会重复创建新的对象。看来这些知识点对日常工作一点帮助都没有,因为你永远不会用is来比较两个整型对象的值。那为什么要提出来讨论呢?那么,程序员不应该停止学习知识,而应该充分发扬死而复生的精神。
