【问题标题】:Python: Different results when using PyCharm and IDLE/pythonPython:使用 PyCharm 和 IDLE/python 时的不同结果
【发布时间】:2016-08-28 06:04:45
【问题描述】:

我刚刚读到“is 运算符的意外结果”,这是因为 Python 缓存数字介于 -5 和 256 之间。

这里讨论过: "is" operator behaves unexpectedly with integers

这里: "is" and "id" in Python 3.5

当我运行其中给出的示例之一时,我在 Python Idle 和 Python IDE 之间得到不同的结果(我使用的是 Jetbrains Pycharm 专业版 - 5.0.4)。

当使用 Python IDLE 时,结果如下:

a = 1000
b = 1000
print (a is b) # prints False

当使用 Pycharm 5.0.4 时,结果如下:

a = 1000
b = 1000
print (a is b) # prints True

这怎么可能? 我已经重新检查过,我的项目的 Python-Interpreter 在这两种情况下都是完全相同的(都是 Python 3.5.1)。 不知道这是否是我做错了什么,我希望有人能解释一下。

编辑:

我知道 'a' 是 'b' == true 如果 id(a) == id(b),并且您可以像 cmets 中提到的一些人一样检查它。也许我应该更清楚一点,我不明白 IDE 怎么会有不同的行为?我认为(请纠正我,因为我似乎错了)IDE 只是一个使用外部编译器/解释器的用户友好环境,这就是为什么这些独立于那些 IDE(例如,pycharm 支持不仅是 Python,我还可以使用 C 编译器或 Java 等运行 Eclipse(所有这些都不是 IDE 的一部分)。

谢谢, 阿隆。

【问题讨论】:

    标签: python python-3.x integer pycharm python-idle


    【解决方案1】:

    来自is operator 的文档:

    运算符isis not 测试对象身份:x is y 为真 当且仅当 x 和 y 是同一个对象。

    现在让我们检查 IDLE:

    >>> a = 1000
    >>> b = 1000
    >>> print ( a is b )
    False
    >>> 
    >>> 
    >>> id(a)
    35334812
    >>> id(b)
    35334800
    

    PyCharm:

    >>> a = 1000
    b = 1000
    print (a is b)
    True
    >>> id(a)
    36079236
    >>> id(b)
    36079236
    

    在 PyCharm 中,ab 在 IDLE 中是相同的对象

    现在在 PyCharm 中引入了什么,如果您逐行输入代码,就像在 IDLE 中一样,您将获得与 IDLE 中相同的结果:

    >>> a = 1000
    >>> b = 1000
    >>> print (a is b)
    False
    

    我猜,那个

    >>> a = 1000
        b = 1000
    

    优化为:

    >>> a = b = 1000
    >>> print (a is b)
    True
    

    这就是为什么 ab 得到相同对象的原因

    【讨论】:

    • 您的猜测可以通过使用 a = 1000; b = 100 + 900 或其他导致整数 1000 的操作进行测试来支持。我认为,这样不应优化引用相同的对象。
    • 是的,我知道 id() 函数,但这并不是我要问的。请看我的更新。并感谢您的回答。
    • 这是因为优化,但不是你想的那样,因为a = 1000; b = None ; c = 1000 也使a is c 正确,你可能想看看my answer
    【解决方案2】:

    如果两个变量指向同一个对象,is 将返回 True, 如果变量引用的对象,== 将返回 True 是平等的。

    在python中,

    >>> a = [1, 2, 3]
    >>> b = a
    >>> b is a 
    True
    >>> b == a
    True
    
    >>> b = a[:]
    >>> b is a
    False
    >>> b == a
    True
    

    那是因为我们将 id(a) 与 id(b) 匹配。

    考虑,

    a = 1000
    b = 1000
    a is b
    

    a is b 将是 False;您对身份的假设仅在 CPython 中适用于 -5 to 256 范围内的数字,出于性能原因,这些数字是单例,但所有其他整数都会根据需要重新创建,而不是单例。

    基于:reference

    【讨论】:

      【解决方案3】:

      这是因为LOAD_CONST 字节码的工作原理:

      co_consts[consti] 推入堆栈。

      由于整数被存储为常量,因此在相同上下文中对相同整数的赋值将产生完全相同的结果,我们可以看到对于 a 和 b 的 LOAD_CONST 的争论是 0

      >>> import dis
      >>> dis.dis("a = 1000 ; b = 1000")     
        1           0 LOAD_CONST               0 (1000)
                    3 STORE_NAME               0 (a)
                    6 LOAD_CONST               0 (1000)
                    9 STORE_NAME               1 (b)
                   12 LOAD_CONST               1 (None)
                   15 RETURN_VALUE
                                             # ^ this is the argument 
      

      在交互式会话中,每个命令都是单独编译的(以便它们可以单独执行),因此常量会有所不同:

      >>> code1 = compile("a = 1000","<dummy file>","exec")
      >>> code2 = compile("a = 1000","<dummy file>","exec")
      >>> code1.co_consts, code2.co_consts
      ((1000, None), (1000, None))
      >>> code1.co_consts[0] is code2.co_consts[0]
      False
      

      同样,一个函数中的常数总是相同的,但与其他函数中的常数不同:

      def f():
          return 1000
      def g():
          return 1000 #different code object!!
      
      #these all work
      assert f() is f()
      assert g() is g()
      assert f() is not g()
      assert f() is not 1000 and g() is not 1000
      

      还请注意,正如@AniMenon 指出的那样,从 -5 到 256 的数字是用于优化的单例,因此对于该范围内的数字而言,情况并非如此。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多