gpt4 book ai didi

详解python中的 is 操作符

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 29 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章详解python中的 is 操作符由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

大家可以与Java中的 == 操作符相互印证一下,加深一下对引用和对象的理解。原问题: Python为什么直接运行和在命令行运行同样语句但结果却不同,他们的缓存机制不同吗?

其实,高票答案已经说得很详细了。我只是再补充一点而已.

is 操作符是Python语言的一个内建的操作符。它的作用在于比较两个变量是否指向了同一个对象.

与 == 的区别 。

?
1
2
3
4
5
6
7
8
9
class A():
  def __init__( self , v):
   self .value = v
  def __eq__( self , t):
   return self .value = = t.value
a = A( 3 )
b = A( 3 )
print a = = b
print a is b

这个结果是True,False。因为我们重写了__eq__方法就使得a, b在比较的时候,只比较它们的value即可。只要它们的value相等,那么a, b就是相等的.

而 is 操作符是判断两个变量是否引用了同一个对象.

同一个对象?

is 的用法说起来其实挺简单的,但是真正用起来,它的难点恰恰就在于判断哪些对象是同一个对象.

看下面的几个测试,先不看结果,自己能答对多少?

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
a = 10
b = 10
print a is b
a = 10.0
b = 10.0
print a is b
a = 10
def f():
  return 10
print f() is a
a = 1000
def f():
  return 1000
print f() is a
a = 10.0
def f():
  return 10.0
print f() is a

嗯。这个结果是True, True, True, False, False。你答对了吗?

这个结果中牵扯到两个问题:第一,就是小整数的缓存,第二,就是pyc文件中CodeObject的组织问题.

Python中把-127到128这些小整数都缓存了一份。这和Java的Integer类是一样的。所以,对于-127到128之间的整数,整个Python虚拟机中就只有一个实例。不管你什么时候,什么场景下去使用 is 进行判断,都会是True,所以我们知道了这两个测试一定会是True

?
1
2
3
4
5
6
7
a = 10
b = 10
print a is b
a = 10
def f():
  return 10
print f() is a

接着,我们重点看下,这两个测试:

?
1
2
3
4
5
6
7
a = 10.0
b = 10.0
print a is b
a = 10.0
def f():
  return 10.0
print f() is a

为什么一个是True,一个是False。要探究这个问题,就要从字节码的角度去分析了。我们先把这个文件编译一下:

?
1
python - m compileall testis.py

然后再使用这个工具查看一下字节码文件:  。

  https:// github.com/hinus/railgu n/blob/master/src/main/python/rgparser/show.py 。

得到这样的输出:

?
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<argcount> 0 < / argcount>
<nlocals> 0 < / nlocals>
<stacksize> 2 < / stacksize>
<flags> 0040 < / flags>
<code>
  6400005a00006400005a01006500006501006b080047486400005a000064
  01008400005a02006502008300006500006b0800474864020053
< / code>
<dis>
1   0 LOAD_CONST    0 ( 10.0 )
    3 STORE_NAME    0 (a)
 
2   6 LOAD_CONST    0 ( 10.0 )
    9 STORE_NAME    1 (b)
 
3   12 LOAD_NAME    0 (a)
    15 LOAD_NAME    1 (b)
    18 COMPARE_OP    8 ( is )
    21 PRINT_ITEM  
    22 PRINT_NEWLINE 
 
5   23 LOAD_CONST    0 ( 10.0 )
    26 STORE_NAME    0 (a)
 
6   29 LOAD_CONST    1 (<code object f>)
    32 MAKE_FUNCTION   0
    35 STORE_NAME    2 (f)
 
8   38 LOAD_NAME    2 (f)
    41 CALL_FUNCTION   0
    44 LOAD_NAME    0 (a)
    47 COMPARE_OP    8 ( is )
    50 PRINT_ITEM  
    51 PRINT_NEWLINE 
    52 LOAD_CONST    2 ( None )
    55 RETURN_VALUE 
< / dis>
<names> ( 'a' , 'b' , 'f' )< / names>
<varnames> ()< / varnames>
<freevars> ()< / freevars>
<cellvars> ()< / cellvars>
<filename> 'testis.py' < / filename>
<name> '<module>' < / name>
<firstlineno> 1 < / firstlineno>
<consts>
  10.0
  <code>
   <argcount> 0 < / argcount>
   <nlocals> 0 < / nlocals>
   <stacksize> 1 < / stacksize>
   <flags> 0043 < / flags>
   <code> 64010053 < / code>
   <dis>
7   0 LOAD_CONST    1 ( 10.0 )
    3 RETURN_VALUE 
   < / dis>
   <names> ()< / names>
   <varnames> ()< / varnames>
   <freevars> ()< / freevars>
   <cellvars> ()< / cellvars>
   <filename> 'testis.py' < / filename>
   <name> 'f' < / name>
   <firstlineno> 6 < / firstlineno>
   <consts>
   None
   10.0
   < / consts>
   <lnotab> 0001 < / lnotab>
  < / code>
  None
< / consts>
<lnotab> 060106010b0206010902 < / lnotab>

大家注意看,整个python文件其实就是一个大的<code>对象,f 所对应的那个函数也是一个<code>对象,这个code对象做为整体是大的<code>对象的consts域里的一个const项。再注意,在大<code>对象里,有10.0这样的一个const项,f 这个<code>对象所对应的conts里呢,也有一个10.0这个浮点数.

当python在加载这个文件的时候,就会完成主<code>里的10.0这个浮点数的加载,生成一个PyFloatObject。也就是说静态的pyc文件的常量表在被加载以后,就变成了内存中的常量表,文件的表里的10.0就变成了内存中的一个PyFloatObject。所以,a, b两个变量都会引用这个PyFloatObject.

但是 f 里的那个10.0呢?它是要等到MAKE_FUNCTION被调用的时候才会真正地初始化。做为 f 方法的返回值,它必然与我们之前所说的主<code>里的10.0不是同一个对象了.

本质上讲,这是Python的一个设计缺陷(例如Java以一个文件为编译单元,共享同一个常量池就会减轻这个问题。但如果跨文件使用 == 操作符,也会出现同样的问题。仍然没有解决这个问题。实际上,我自己也不知道该怎么解决这个问题。)我们应该尽量避免 is 的这种用法。始终把 is 的用法限制在本文的第一个例子中。这样相对会安全一些.

原文链接:https://zhuanlan.zhihu.com/p/32351552?utm_source=tuicool&utm_medium=referral 。

最后此篇关于详解python中的 is 操作符的文章就讲到这里了,如果你想了解更多关于详解python中的 is 操作符的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com