id()vs`is`运算符.比较`id`s是否安全?相同的`id`是否意味着同一个对象?

iva*_*eev 6 python identity identity-operator

我可以id()在实践中依赖对象及其独特性多少?例如:

  • 是否id(a) == id(b)意味着a is b反之亦然?对面怎么样?
  • 保存id以后要使用的某个地方(例如进入某个注册表而不是对象本身)有多安全?

(作为对Canonicals for Python的响应而写成的规范:具有相同id()的对象是相同的对象,`is`运算符,未绑定的方法对象)

iva*_*eev 7

根据id()文档,id只保证是唯一的

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

因此,比较ids是不安全的,除非你还以某种方式确保在比较时两个id被拍摄的对象仍然存活(并且与相同的Python解释器实例相关联,但你需要真正尝试使其变为false) ).

这究竟是什么is- 这使得比较id多余.如果is由于某种原因你不能使用语法,总会有operator.is_.


现在,一个物体是否还活着,在比较时并不总是显而易见的(有时是非常 -obvious):

  • 访问某些属性(例如,对象的绑定方法)每次都会创建一个新对象.因此,id每个属性访问的结果可能相同也可能不同.

    例:

    >>> 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
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果一个对象是由于计算表达式而未保存在任何地方而创建的,则会立即将其丢弃,1并且之后创建的任何对象都可以占用它id.

    • 在同一代码行中甚至是这样.例如结果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
      
      Run Code Online (Sandbox Code Playgroud)

由于上述比较ids 时的安全要求,保存id而不是对象不是很有用,因为你必须保存对象本身的引用 - 以确保它保持活着.两者都没有任何性能提升:is实现就像比较指针一样简单.


最后,作为内部优化(以及实现细节,因此实现和发布之间可能不同),CPython重用了一些常用的简单对象,这些对象是不可变类型.在撰写本文时,它包括小整数一些字符串.因此,即使你从不同的地方获得它们,它们id的可能也会重合.

这(技术上)不违反上述id()文档的唯一性承诺:重用的对象在所有重用中保持活跃.

这也不是什么大问题,因为两个变量是否指向同一个对象只是实际知道对象是否可变:如果两个变量指向同一个可变对象,那么变异将(意外地)改变另一个变量.不可变类型没有那个问题,因此对于它们来说,如果两个变量指向两个相同的对象或同一个对象并不重要.


1 有时,这被称为"未命名的表达".