Python中对象包含的三个基本要素:id(身份标识),type(数据类型),value(值)python
x = y = [1, 2, 3] z = [1, 2, 3] print(x == y) # True print(x == z) # True print(x is y) # True print(x is z) # False print(id(x)) # 4416785008 print(id(y)) # 4416785008 print(id(z)) # 4416784504
对于整数对象,Python把一些频繁使用的整数对象缓存起来,保存到一个叫small_ints
的链表中,在Python的整个生命周期内,任何须要引用这些整数对象的地方,都再也不从新建立新的对象,而是直接引用缓存中的对象。Python把这些可能频繁使用的整数对象规定在范围[-5, 256]之间的小对象放在small_ints
中,但凡是须要用些小整数时,就从这里面取,再也不去临时建立新的对象。缓存
一、当整数对象在区间[-5,256]内时,is获得的结果是True(a,b的id值相同)函数
二、当整数对象不在区间[-5,256]内时,is获得的结果是False(a,b的id值不一样)性能
三、看懂上面两个例子后,咱们接着看如下代码:spa
c = 257 def test(): a = 257 b = 257 print(a is b) # True print(a is c) # False print(id(a)) # 140644774393856 print(id(b)) # 140644774393856 print(id(c)) # 140644774394072 test()
若是按照第2点得出的结论,257不在区间[-5,256]内,那么两个的is结果都应该为False才对,但是为何a is b却为True呢?code
为了弄清楚这个问题,首先咱们要先理解程序的代码块问题。Python程序由代码块构成,代码块做为程序的一个最小基本单位来执行。一个模块文件、一个函数体、一个类、交互式命令中的单行代码都叫作一个代码块。在上面这段代码中,由两个代码块构成,c = 257
做为一个代码块,函数test做为另一个代码块。Python内部为了将性能进一步的提升,凡是在一个代码块中建立的整数对象,若是存在一个值与其相同的对象于该代码块中了,那么就直接引用,不然建立一个新的对象出来。Python出于对性能的考虑,但凡是不可变对象,在同一个代码块中的对象,只有是值相同的对象,就不会重复建立,而是直接引用已经存在的对象。所以,不只是整数对象,还有字符串对象也遵循一样的原则。因此 a is b
就理所固然的返回True
了,而c
和a
不在同一个代码块中,所以在Python内部建立了两个值都是257的对象。对象
注:以下图所示,在PyCharm中运行以下代码,获得的结果都为True,缘由就是由于在同一代码块中,值相同的对象就不会重复建立,而是直接引用已经存在的对象生命周期
a = 1 # a和b为数值类型,在区间[-5,256]内 b = 1 print(a is b) # True print(id(a)) # 140586619260200 print(id(b)) # 140586619260200 a = 257 # a和b为数值类型,不在区间[-5,256]内 b = 257 print(a is b) # True print(id(a)) # 140586619294392 print(id(b)) # 140586619294392
当a,b为字符串对象时,python中有intern机制,它指的就是在建立一个新的字符串对象时,若是已经有了和它的值相同的字符串对象,那么就直接返回那个对象的引用,而不返回新建立的字符串对象。只包括字母数字下划线的字符串,python会对它们使用intern机制。(因此当字符串只包括字母数字下划线时,进行is操做返回True,若是包含其余字符,进行is操做则返回False)字符串
a = "a_1" # a和b为字符串类型 b = "a_1" print(a is b) # True print(id(a)) # 4454524688 print(id(b)) # 4454524688 a = "&" # a和b为字符串类型 b = "&" print(a is b) # True print(id(a)) # 4305008120 print(id(b)) # 4305008120
注:当a,b为单个字符对象时,进行is操做都返回Truetest
当a,b为元组,list,dict和set类型时,进行is操做结果为False
a = (1, 2, 3) # a和b为元组类型 b = (1, 2, 3) print(a is b) # False print(id(a)) # 4366076016 print(id(b)) # 4366076416 a = [1, 2, 3] # a和b为list类型 b = [1, 2, 3] print(a is b) # False print(id(a)) # 4366191216 print(id(b)) # 4366190712 a = {'is' : 1, 'equal' : 2} # a和b为dict类型 b = {'is' : 1, 'equal' : 2} print(a is b) # False print(id(a)) # 4365197952 print(id(b)) # 4366187608 a = ([1, 2, 3]) # a和b为set类型 b = ([1, 2, 3]) print(a is b) # False print(id(a)) # 4366190712 print(id(b)) # 4366191216