2016-02-03 25 views
13

我想,is运算符检查对象id的平等。但似乎并非如此。你持有的对象没有其他引用,一旦id(a.f)评估有对象的更多引用故gc'd那么Python是免费的重复使用相同的内存位置为什么同一对象的不同方法具有相同的`id`?

>>> class A(object): 
... def f(): return 1 
... def g(): return 2 
... 
>>> a = A() 
>>> a.f is a.g 
False 
>>> id(a.f) == id(a.g) 
True 

回答

14

Python中重复使用相同的内存位置为a.g。如果您分配方法的名称,你会看到不同的行为:

# creates a reference to the method f 
In [190]: f = a.f 
# creates a reference to the method g 
In [191]: g = a.g 
# cannot reuse the memory location of f as it is still referenced 
In [192]: id(f) == id(g) 
Out[192]: False 

实际上,你真的只需要存储到f参考,看看与上面相同的行为。

In [201]: f = a.f 

In [202]: id(f) == id(a.g) 
Out[202]: False 

你可以看到引用计数与sys.getrefcountgc.gc.get_referrers

In [2]: import gc 

In [3]: f = a.f 

In [4]: len(gc.get_referrers(a.g)),len(gc.get_referrers(f)) 
Out[4]: (0, 1) 

In [5]: sys.getrefcount(a.g),sys.getrefcount(f) 
Out[5]: (1, 2) 

你AG看到1的唯一原因是因为返回的计数是通常一个高于你所期望的,因为它包含(临时)引用作为getrefcount()的参数。 这是类似于你自己的例子,在方法评估后,你仍然可以参考fa.g refcount将为0,因此它立即被垃圾收集,python可以自由地使用内存位置用于其他任何事情。

还值得一提的是,该行为并不局限于方法,但它只是一个CPython的实现细节,不是说你应该永远依靠的东西:

In [67]: id([]), id([]) 
Out[67]: (139746946179848, 139746946179848) 

In [73]: id(tuple()),id([]),id([]) 
Out[73]: (139747414818888, 139746946217544, 139746946217544) 

In [74]: id([]),id([]),id([]) 
Out[74]: (139746946182024, 139746946182024, 139746946182024) 

In [75]: id([]),id(tuple()),id([]) 
Out[75]: (139746946186888, 139747414818888, 139746946186888) 

In [76]: id(tuple()),id([]),id(tuple()) 
Out[76]: (139747414818888, 139746946217736, 139747414818888) 
+0

这是我的理解空的元组是单(实现细节)。所以这不像空列表的例子那样有趣,对我来说无论如何。 –

4

相同的内存位置正在使用通过python的方法a.fa.g,这是**两个对象具有无重叠的生存期*,所以id返回相同的身份为他们两个,请参阅下面的更详细的解释。

从文档为is operator

的运营商是并没有测试对象标识:x是y为真 当且仅当x和y是相同的对象。

从用于文档是id

返回的对象的“身份”。这是一个整数(或整数长度为 ),对于此对象在其生命周期中为 保证是唯一且恒定的。 具有非重叠生存期的两个对象可能有 具有相同的id()值。

说明: 当你通过class.nameinstance.name查找的方法,该方法对象被创建一个新的。 Python使用descriptor protocol每次将函数包装在方法对象中。

因此,当您查找id(a.f)id(a.g)时,会创建一个新的方法对象。

  1. 当你编号为a.f时,它的一个副本被创建在内存中。该内存位置由id
  2. 既然有新创建的方法没有引用返回,其回收由GC(现在内存地址再次可用
  3. 你得到的a.g ID,它的一个副本后,在相同的内存地址,您检索再次使用id
  4. 你有truthy ID的比较

缺乏良好的创建!

2

a.f和a.g是不同的对象。
是运算符只有当它们是一个对象时才返回true。 但是具有非重叠生存期的两个对象可能具有相同的id()值。

参阅here为ID操作者

2

操作is检查对象标识不值,并且在这种情况下,你有两个单独的功能(对象),因此它们具有不同的身份。

约在以下部分:

>>> id(a.f) == id(a.g) 
True 

由于蟒蛇在运行时创建的对象首次蟒蛇试图获得a.fa.g ID中没有被定义并基于Python的维基具有非重叠生命周期的两个对象可能具有相同的id()值。因此在这种情况下,具有非重叠寿命的对象a.fa.g具有相同的ID。

返回对象的“身份”。这是一个整数(或整数长度为 ),对于此对象在其生命周期中为 保证是唯一且恒定的。具有非重叠生存期的两个对象可能具有相同的id()值。

is操作一些额外的注意事项:

正如我在前面提到的行表示运营商将检查对象和对象的Python中的身份将在运行时创建的。但是对于像整数和字符串这样的小类型来说这不是真的,因为你是单独的而不是python对象。因此,这个将会像C类型一样被定位在内存中。

为了更好的演示中,您可以看到下面的例子:

>>> 100 is 10*10 
True 
>>> 
>>> 1000 is 10*100 
False 
>>> 

而对于字符串:

>>> 'aaaa'*5 is 'a'*20 
True 
>>> 'aaaa'*50 is 'a'*200 
False 
相关问题