两个Python对象如何具有相同的id,但是'is'运算符返回False?

时间:2018-06-17 02:47:43

标签: python object lifetime

id(t+t), id(t*2)
(42838592, 42838592)

(t+t) is (t*2)
False

如果两个变量指向同一个对象'是',则运算符将返回true。但是第一行表示两者具有相同的id但是'is'运算符给出false值。

2 个答案:

答案 0 :(得分:6)

在第一个示例中,您的对象不会在时间上重叠:一个创建然后销毁,然后另一个创建具有相同的ID。

当您将它们与is进行比较时,您将抓住这两个对象,因此它们会得到不同的ID。

答案 1 :(得分:3)

Ned Batchelder's answerthe docs for the id function解释:

  

两个具有非重叠生命周期的对象可能具有相同的id()值。

这两个对象的生命周期不重叠。

他们属于同一元组表达式的事实并没有改变它,因为它不是t+tt*2的元组的一部分,它是id(t+t)id(t*2)。因此,id返回的这两个整数值具有重叠的生命周期,但传递给id的参数不会。

了解这一点的一种方法是查看CPython如何编译代码:

>>> dis.dis('id(t+t), id(t*2)')
  1           0 LOAD_NAME                0 (id)
              2 LOAD_NAME                1 (t)
              4 LOAD_NAME                1 (t)
              6 BINARY_ADD
              8 CALL_FUNCTION            1
             10 LOAD_NAME                0 (id)
             12 LOAD_NAME                1 (t)
             14 LOAD_CONST               0 (2)
             16 BINARY_MULTIPLY
             18 CALL_FUNCTION            1
             20 BUILD_TUPLE              2
             22 RETURN_VALUE

所以,这里发生了什么。 (我要为t选择一个值,比如1000,只是为了让这更容易理解。)

  • id10001000被推入堆栈。
  • BINARY_ADD在位置2000创建42838592值。
  • id会在该值上调用并在位置返回42838592值,例如42838616
  • 由于42838592值不再存在于堆栈中并且未存储在任何位置,因此id的参数是对它的唯一引用,因此当它被减少时在功能结束时,它会立即删除。
  • id10002被推入堆栈。
  • BINARY_MULTIPLY创建一个新的2000对象。由于位置42838592刚刚返回到对象池,因此新值将重用该位置。
  • id会返回另一个42838592,这次是在42838640

因此,两个int42835924283592的生命周期重叠(第一个与第二个2000重叠),两个2000 s不重叠。

最后,请注意,如果t是一个小数字,

>>> t = 2
>>> (t+t) is (t*2)
True

...因为所有4值(除非在特殊情况下)都是对同一对象的引用。

同时,如果t是常量而不是变量,1000+1000 is 1000*2可能会或可能不会,这取决于您的CPython版本,因为编译单元中的常量折叠的工作方式。

所有这些都表明,试图真正利用两个相等的int是否是同一个对象,这几乎总是一个可怕的想法。你应该关心这个问题的唯一原因是你是否想要更多地了解CPython的内部结构。

当然这都是CPython特有的。大多数其他Python解释器使用某种形式的垃圾收集器而不是引用计数,因此第一个2000在创建第二个id之前不太可能被销毁。另外,并非所有人都使用像CPython这样的对象池。更不用说他们可以为t+t做完全不同的事情,只要他们可以保证非重叠对象的唯一值。

PyPy实际上通常会在这里返回相同的值 - 但这只是因为它首先将t*2t+t折叠到同一个对象中;尝试使用and you'll get completely different和t * 3 <label for="category">Category</label> <select id="categories" class="form-control" [formControlName]="category" value="Select category" name="category"> <option value="">Select category (skills, interests, locations)</option> <option *ngFor="let category of categories" [value]="category.id">{{category.name}}</option> </select> id`s。