代码之家  ›  专栏  ›  技术社区  ›  ivan_pozdeev RenanSS

id()vs`is`运算符。比较“id”是否安全?相同的“id”是否表示相同的对象?

  •  6
  • ivan_pozdeev RenanSS  · 技术社区  · 6 年前

    我能依靠物体的多少 id() 它在实践中的独特性?例如。:

    • id(a) == id(b) 意思是 a is b 反之亦然?相反呢?
    • 拯救一个 id 以后要使用的地方(例如,在某个注册表中而不是对象本身)?

    (作为一个建议的规范,以响应 Canonicals for Python: are objects with the same id() the same object, `is` operator, unbound method objects )

    1 回复  |  直到 5 年前
        1
  •  7
  •   ivan_pozdeev RenanSS    5 年前

    根据 id() documentation ,一个 id 只保证独一无二

    1. 在特定对象的生命周期内,以及
    2. 在特定的解释器实例中

    像这样的, 比较 身份证件 S是不安全的,除非你也以某种方式确保 身份证件 在比较时,S仍然活着。 (并且与同一个Python解释器实例相关联,但您需要真正尝试使其变为假)。

    这正是什么 is 是——这使得比较 身份证件 多余的。如果您不能使用 不管出于什么原因,总是有 operator.is_ .


    现在, 在比较时一个对象是否还活着并不总是显而易见的。 (有时 -明显的:

    • 访问某些属性 (例如) bound methods of an object ) 每次创建一个新对象。 所以,结果是 身份证件 在每个属性访问上可能相同,也可能不同。

      例子:

      >>> class C(object): pass
      >>> c=C()
      >>> c.a=1
      
      >>> c.a is c.a
      True        # same object each time
      
      >>> c.__init__ is c.__init__
      False       # a different object each time
      
      # The above two are not the only possible cases.
      # An attribute may be implemented to sometimes return the same object
      # and sometimes a different one:
      @property
      def page(self):
          if check_for_new_version():
              self._page=get_new_version()
          return self._page
      
    • 如果对象 是由于计算表达式而创建的,而不是保存在任何位置,它会立即被丢弃, 之后创建的任何对象 身份证件 .

      • 在同一代码行中也是如此。例如,结果 id(create_foo()) == id(create_bar()) 是未定义的。

        例子:

        >>> id([])     #the list object is discarded when id() returns
        39733320L
        >>> id([])     #a new, unrelated object is created (and discarded, too)
        39733320L      #its id can happen to be the same
        >>> id([[]])
        39733640L      #or not
        >>> id([])
        39733640L      #you never really know
        

    由于上述安全要求,比较时 身份证件 s,保存一个 身份证件 相反,对象并不是很有用,因为您无论如何都必须保存对对象本身的引用——以确保它保持活动。也没有任何性能提升: is implementation is as simple as comparing pointers .


    最后,作为一个内部优化(和实现细节,因此在实现和发布之间可能有所不同),CPython重用了一些经常使用的不可变类型的简单对象。在本文中,包括 small integers some strings . 所以即使你从不同的地方得到它们, 身份证件 S可能重合。

    这不会(技术上)违反上述规定 () 文档的唯一性保证:重用对象在所有重用过程中都保持活动。

    这也没什么大不了的,因为两个变量是否指向同一个对象只是为了知道对象是否可变: if two variables point to the same mutable object, mutating one will (unexpectedly) change the other, too . 不可变类型没有这个问题,所以对于它们来说,两个变量是指向两个相同的对象还是指向同一个对象并不重要。


    有时,这被称为“未命名的表达”。