python中id函数 is命令_python中关于 id 函数、 is 和 == 的理解

在编写python程序时,我们经常会用到id() 、is 和 ==,他们之间在某些情况得到的结果相同,有些情况下结果却不同。对id() 、is 和 ==的理解,实际上就是对python内存分配的理解。

is和==还是比较容易区分理解的。

is运算符判断两个运算对象的标志号是否相同,也就是判断是否引用自同一对象。

==运算符判断两个运算对象的值是否相同。

例如:

1

2

3

4[] is []

False

[] == [] # 但是它们的值是相同的,都为空。

True

id()和is

先来看看python docs 里关于id() 和 is 的说明

id(object)

返回对象的“标识值”。该值是一个整数,在此对象的生命周期中保证是唯一且恒定的。两个生命周期不重叠的对象可能具有相同的 id()值。

CPython implementation detail: This is the address of the object in memory.

is

运算符 is 和 is not 用于检测对象的标识号:当且仅当 x 和 y 是同一对象时 x is y 为真。 一个对象的标识号可使用 id() 函数来确定。 x is not y 会产生相反的逻辑值。

id()很好理解了,就是获取一个标识值,该值相当于对象在内存堆中的地址。

is按照官方文档解释好像就相当于id(obj1) == id(obj2),用来判断id值是否相等。多数情况下确实如此,来看看如下例子。

来运行几行代码测试看看:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20# MAGIC !

1.>>> a = "string"

>>> id(a)

1343539021560

2.>>> id("str" + "ing")

1343539021560

>>> a1 is "str"+"ing"

True

3.>>> b1 = "A string"

>>> id(b1)

1672155110256

4.>>> b2 = "A str"+"ing"

>>> id(b2)

1672154162864

5.>>> "A string" is "A str"+"ing"

True

6.>>> id("A string")

1675616747440

7.>>>id("A str"+"ing")

1675616809072

​ 运行上述代码会发现一些很奇怪的问题…

​ 这是由于python的官方解释器Cpython的实现里有许多编译优化,其中一个就是字符串驻留机制(string interning)。基于这个机制,python在创建一个新的字符串对象时,某些情况下(例如只包含数字、字母和下划线的字符串、长度为0或者1的字符串、编译时)会直接使用已创建的对象,只要它们的值相同即可。这样可以节省内存(节约个屁,总共就省几十个字节的空间),更多的是减少了创建和销毁对象的次数。

​ 所以1和2结果是一样的。对于3和4,字符串中包含有空格,不会触发string interning,因此b1和b2指向不同的内存空间。

​ 5运行实际上也触发了字符串驻留机制;再次输出id值,id("A string")确实和id("A str"+"ing")不一样(其实这样做是没有意义的,再次输出id值验证倒有点偷换概念的样子)。原因如下:在5的表达式运算中,"A str"+"ing"是编译(compile)时求值,同样会触发字符串驻留机制,"A str"+"ing"被替换成了A string.

​ 实际上,不仅仅时string interning会有这种奇怪的结果,python对于整数存储的优化也会带来这种奇怪的现象。当你启动python程序时,常使用的整数-5到256就已经被预先分配好了内存。当你使用256这个整数时,不过是将一个变量引用指向了已经存在的整型对象(值为256),不管使用多少个256,它们都指向的是那个预先创建好的对象。如下:

1

2

3

4

5

6

7

8

9

10

11

12a = 256

b = 256

c = 257

>>>d = 257

>>>a is b

True

>>>id(a) == id(b)

True

>>>c is d

False

>>>id(c) == id(d)

False

也就是说,在多数情况下我们可以这样理解:is相当于id(obj1) == id(obj2),具有判断id值是否相等的作用。

BUT

需要注意的是,官方文档中还有一句话 “ 两个生命周期不重叠的对象可能具有相同的 id()值。”

就是说就算对象不一样还是会存在id值相同的情况???

再看看下面的代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46# MAGIC AGAIN !

class :

def a(self):

pass

@classmethod

def b():

pass

class B:

def a(self):

pass

@staticmethod

def b():

pass

class C(A):

def a(self):

pass

@staticmethod

def c():

pass

a = A()

b = B()

c = C()

print(id(a.a))

print(id(a.b))

print(id(b.a))

print(id(b.b))

print(id(c.a))

print(id(c.b))

print(id(c.c))

############## console ##############

1675615763208

1675615763208

1675615763208

1675616546600

1675615763208

1675615763208

1675616579792

​ 确实是如此!不管是同一个类还是不同类,抑或是父子类的方法id值都存在一样的情况。

​ 这里先简要提一下python的对象垃圾回收策略:python在创建对象时会同时生成一个数字用来记录对象的引用计数,例如a="string"语句执行后变量a指向“string”对象,“string”对象的引用计数为1,当再执行a=6后变量a指向6,“string”对象的引用计数就会减1变成0,于是“string”就会被当作垃圾回收掉。

​ 在上述代码中,我们并没有对x.x的方法调用进行引用赋值,它们在各自执行完所在行语句后就被回收掉了,各自生命周期不重叠。至于id值为什么会一样,我们可以理解为固定有那么一块内存,它存放一个类或者方法,用哪个存哪个,用完被垃圾回收掉的就不管了,这块内存继续用来存下一个或某个调用的类或方法。

大多数情况下is表达式运算确实相当于id(obj1) == id(obj2),但是这其中还有一点限制需要注意,如果没注意到这个限制,那么is可能给你意想不到的结果。这个限制就是is判断的两个对象的生命周期是有重叠部分的。看看如下代码(接上一个代码块)

1

2

3

4

5

6

7# MAGIC AGAIN !

print(id(a.a)==id(a.b)==id(b.a)==id(c.a))

print(a.a is a.b)

############## console ##############

True

False

​ 一步一步来解释这两行代码:

​ 首先第一行是一个表达式的计算,按照从左到右、从内到外并遵从运算优先级(这里没有其他运算符,不用考虑优先级)的顺序,先调用a.a,传给id,最后得到一个整数,由于a.a的引用计数为0,所以原先存a.a的内存腾出来可以用在其他地方;再计算id(a.b)得到一个整数(a.b很可能存放在之前a.a存放的内存空间中),并且也触发了垃圾回收,下略。由于都存放在同一内存空间中,这些整数都相同,最后结果自然为True

​ 第二行代码表达式从左到右求值,我们可以理解为调用a.a放在内存某个空间中并用一个临时变量tmp1(如此假设而已)指向它,调用a.b放在内存某个空间中并用一个临时变量tmp2指向它,这个步骤决定is接收的两个对象生命周期存在重叠部分,既然生命周期存在重叠部分并且单元内存又不能同时存放两个对象,那么is运算时两个对象都在不同内存中,结果自然是False。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值