7

在实践中我能在多大程度上依赖对象的id()独特性?例如:

  • 是什么id(a) == id(b)意思a is b,反之亦然?相反的呢?
  • 保存某个id地方以供以后使用(例如,保存到某个注册表而不是对象本身)有多安全?

(作为对 Python 规范的回应而编写的规范建议:对象是否具有相同的 id() 相同的对象,`is` 运算符,未绑定的方法对象

4

1 回答 1

8

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

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

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

这正是is它所做的——这使得比较变得id多余。is如果您出于某种原因无法使用该语法,则始终存在operator.is_.


现在,一个对象在比较时是否还活着并不总是很明显(有时非常不明显):

  • 每次访问某些属性(例如对象的绑定方法都会创建一个新对象。因此,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
    
  • 如果一个对象是作为计算表达式的结果创建的并且没有保存在任何地方,它会立即被丢弃,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
      

由于比较ids 时的上述安全要求,保存 anid而不是对象并不是很有用,因为无论如何您都必须保存对对象本身的引用——以确保它保持活动状态。也没有任何性能提升:is实现就像比较指针一样简单


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

这并不(技术上)违反上述id()文档的唯一性承诺:重用的对象在所有重用过程中保持活动状态。

这也没什么大不了的,因为两个变量是否指向同一个对象只有知道对象是否可变才是实际的:如果两个变量指向同一个可变对象,变异一个也会(出乎意料地)改变另一个. 不可变类型没有这个问题,所以对于它们来说,两个变量指向两个相同的对象还是指向同一个对象都没有关系。


1有时,这称为“未命名表达式”。

于 2018-09-11T03:43:25.223 回答