代码之家  ›  专栏  ›  技术社区  ›  U13-Forward

为什么`;`分隔行得到的结果是'True',但是没有结果就没有?-蟒蛇[复制]

  •  0
  • U13-Forward  · 技术社区  · 6 年前

    在使用Python解释器时,我偶然发现了一个关于 is 操作员:

    True ,如果在外部完成,则返回 False

    >>> def func():
    ...     a = 1000
    ...     b = 1000
    ...     return a is b
    ...
    >>> a = 1000
    >>> b = 1000
    >>> a is b, func()
    (False, True)
    

    自从 运算符计算 id() 对于涉及的对象,这意味着 a b 指向相同的 int func 但是,恰恰相反,它们指向的是另一个物体,当它在它之外。


    注意 :我知道身份之间的区别( )平等( == )操作如中所述 Understanding Python's "is" operator . 此外,我还知道python正在为范围内的整数执行缓存 [-5, 256] 如中所述 "is" operator behaves unexpectedly with integers .

    这个 情况不是这样吗 因为数字不在这个范围内 我愿意 平等。

    0 回复  |  直到 7 年前
        1
  •  61
  •   Dimitris Fasarakis Hilliard    7 年前

    日间;夜间:

    作为 reference manual

    以下是块:模块、函数体和类定义。

    这就是为什么在函数的情况下 单一的 包含 对象作为数值文本 1000 ,所以 id(a) == id(b) 会屈服的 True

    在第二种情况下,你有 两个不同的代码对象 所以 id(a) != id(b) .

    int float 文字(请参见 here

    当然,比较对象(除了显式 is None 测试)应始终使用相等运算符 == is .

    这里所述的一切都适用于最流行的Python实现CPython。其他实现可能会有所不同,因此在使用它们时不应作出任何假设。


    更长的答案:

    以获得更清晰的视图并进一步验证这一点 看起来很奇怪 code 对象 dis

    对于函数 func :

    __code__ 属性,该属性允许您查看该函数的已编译字节码。使用 dis.code_info

    >>> print(dis.code_info(func))
    Name:              func
    Filename:          <stdin>
    Argument count:    0
    Kw-only arguments: 0
    Number of locals:  2
    Stack size:        2
    Flags:             OPTIMIZED, NEWLOCALS, NOFREE
    Constants:
       0: None
       1: 1000
    Variable names:
       0: a
       1: b
    

    我们只对 Constants 函数 . 从中我们可以看出我们有两个价值观, None (始终在场)和 1000 . 我们只有一个 单一的 表示常量的int实例 . 这就是 a b

    通过 func.__code__.co_consts[1] 从另一个角度来看 a is b

    >>> id(func.__code__.co_consts[1]) == id(func.__code__.co_consts[1]) 
    

    当然,它的评估结果 是的 因为我们指的是同一个物体。

    对于每个交互式命令:

    如前所述,每个交互式命令都被解释为一个单独的代码块:独立地解析、编译和计算。

    compile 内置:

    >>> com1 = compile("a=1000", filename="", mode="single")
    >>> com2 = compile("b=1000", filename="", mode="single")
    

    对于每个赋值语句,我们将得到一个类似的代码对象,如下所示:

    >>> print(dis.code_info(com1))
    Name:              <module>
    Filename:          
    Argument count:    0
    Kw-only arguments: 0
    Number of locals:  0
    Stack size:        1
    Flags:             NOFREE
    Constants:
       0: 1000
       1: None
    Names:
       0: a
    

    com2 :每个代码对象 com1 通信2 有不同的int实例来表示文本 . 这就是为什么,在这种情况下 a是b 通过 co_consts

    >>> id(com1.co_consts[0]) == id(com2.co_consts[0])
    False
    

    不同的代码对象,不同的内容。


    注:

    co_consts 属性由dictionary对象表示。在 compile.c 我们可以看到初始化:

    /* snippet for brevity */
    
    u->u_lineno = 0;
    u->u_col_offset = 0;
    u->u_lineno_set = 0;
    u->u_consts = PyDict_New();  
    
    /* snippet for brevity */
    

    在编译期间,会检查已经存在的常量。看到了吗 @Raymond Hettinger's answer below


    注意事项:

    • 链式语句将对 是的

      现在应该更清楚为什么下面的计算结果 是的

      >>> a = 1000; b = 1000;
      >>> a is b
      

      在一起 将创建一个 是的 评估时的值。

    • 是的 再一次:

      如前所述,参考手册规定:

      ... 以下是块: a模块 ...

    • 相同的 可变的 物体:

      a = []; b = []
      a is b  # always returns false
      

      the documentation ,具体如下:

      在a=1;b=1之后,a和b可以引用值为1的同一对象,也可以不引用,具体取决于实现,但是在c=[];d=[]之后,c和d保证引用两个不同的、唯一的、新创建的空列表。

        2
  •  18
  •   Raymond Hettinger    8 年前

    在交互提示下,输入是 compiled in a single mode 一次处理一个完整的语句。编译器本身(在 Python/compile.c u_consts

    compiler_add_o() 函数,可以看到在添加新常量(并递增索引)之前,将检查dict以查看常量对象和索引是否已经存在。如果是这样,它们将被重用。

    简而言之,这意味着一个语句中的重复常量(例如在函数定义中)被折叠成一个单例。相反,你的 a = 1000 b = 1000 是两个独立的语句,所以不会发生折叠。

    FWIW,这只是一个CPython实现细节(也就是说,语言不保证)。这就是为什么这里给出的引用是C源代码,而不是语言规范,它对这个主题没有任何保证。