【问题标题】:Why should "num3 is num4" result in False? [duplicate]为什么“num3 is num4”会导致 False? [复制]
【发布时间】:2020-01-21 02:08:12
【问题描述】:

Instagram 上有this 的帖子,作者说如果num3num4 设置为257 并且num3 is num4 被评估,你应该得到False

我已经修改了添加一些条件的代码,但我得到了True。我看到直到 256 的整数被分配了相同的内存桶以获得相同的值,但不是 257 以后的整数。那么发生了什么?

num1 = 256
num2 = 256

if num1 == num2:
    print(True)

num3 = 257
num4 = 257

if num3 == num4:
    print(True)
    if num3 is num4:
        print(True)
    else:
        print(False)

【问题讨论】:

  • 257 完全等于 257。不太清楚为什么人们会不这么认为。
  • 试试 python3 REPL。输入 num3=257,然后输入 num4=257。然后键入 num3 is num4 可以看到结果为 False。现在,运行 OPs 程序并注意if num3 is num4 返回True。解释这将有助于OP的答案。
  • 是的,这是一个很好的观点@mkrieger1。从描述看来,OP 想要了解 ==is 对 256 和 257 的比较。我觉得有趣的是,REPL 给出了与 OPs 程序不同的结果。

标签: python python-3.x int python-internals


【解决方案1】:

如果两个变量指向同一个对象,则返回 True

== 如果变量引用的对象相等。

在脚本中运行:

返回真

因为 num3 和 num4 都指向同一个对象:

# id() to get the unique identifier of an object    
print(id(num3) , id(num4)) 

55080624 55080624

== 也返回 True

num3 = 257
num4 = 257

两者都指<class 'int'> 257

在 REPL 中运行:

返回假

因为 num3 和 num4 都指向不同的对象:

# id() to get the unique identifier of an object    
print(id(num3) , id(num4)) 

34836272 39621264

== 返回真

num3 = 257
num4 = 257

两者都指<class 'int'> 257

你得到不同结果的原因来自Why does the `is` operator behave differently in a script vs the REPL?

当您在 .py 脚本中运行代码时,整个文件被编译成一个 代码对象在执行之前。在这种情况下,CPython 能够使 某些优化——比如对整数重用相同的实例 300.

因此,在您的情况下,num3 和 num4 都引用 <class 'int'> 257。在 REPL 中你有不同的对象 id,但是如果你在脚本中运行它们,在文件被编译并优化为相同的对象 id 之后。

关于256和257的不同行为:

"is" operator behaves unexpectedly with integers

What's with the integer cache maintained by the interpreter?

简而言之,表示值从 -5 到 +256 的对象是在启动时创建的,因此如果您的数字范围为 -5 到 256,那么对于任何 int 256,您在 REPL 中都会获得相同的对象 ID,它们将被分配给一个新的对象 ID。

例如:

num5 = -6
num6 = -6 

print(id(num5),id(num6))

39621232 39621136

num7 = 258
num8 = 258

print(id(num7),id(num8))

39621296 39621328

【讨论】:

  • 你知道为什么在 REPL num3 is num4 中返回 False 但是当作为 .py 文件运行时返回 True 吗?
  • 天哪。这太有趣了!感谢分享!
【解决方案2】:

如果你再看帖子,你会发现num3 == num4 是 True,但是 num3 is num4 是 False。这与项目 ID 有关。 == 比较变量的值,而 is 比较它们的 id。您可以使用id(num3)id(num4) 查看他们的每个ID。当值高于 256 时,它们应该是不同的。原因是 Python 会自动存储低数值,并且分配给这些低数值的变量将指向相同的 id。 Python 这样做是因为它们非常常用。但是在 Python 需要它们之前,不会创建更大的数字。所以变量都有自己的 id。

编辑:

运行脚本与 REPL 时的行为似乎有所不同。最初的 Instagram 帖子使用的是 REPL,我使用 REPL 复制了 False 比较。不过,运行脚本对我来说是 True。

【讨论】:

  • 运行 OP 的程序并注意 if num3 is num4 的结果是 True 而不是 False
  • @zedfoxus 我在 Python 3.5.2 和 Python 3.8.1 中运行它,最后打印的内容(即num3 is num4)在两个版本中都是False。你得到的是哪个版本的True
  • 我在 OSX 上使用Python 3.7.4 (default, Sep 7 2019, 18:27:02) 。在 REPL 中我得到 False。当使用python3 file.py 运行程序时,我得到了 True。
  • 我明白了。我的怀疑是,当从同一个代码对象引用时,相同的常量会被重复数据删除,但在从不同的代码对象引用时不会被重复数据删除。脚本被编译成一个代码对象,REPL 中的每一行都被编译成自己的代码对象。
  • 是的,Raymond 分享了一个链接作为对他的回答的评论,这帮助我意识到 CPython 可能如何引用 @kaya3。太有趣了。
猜你喜欢
  • 1970-01-01
  • 2015-09-30
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
  • 2021-10-20
  • 1970-01-01
  • 2016-02-06
  • 1970-01-01
相关资源
最近更新 更多