id()函数用于什么?

时间:2013-03-27 18:58:15

标签: python

我看了the Python 2 docs并注意到了id()函数:

  

返回对象的“标识”。这是一个整数(或长整数),保证在该生命周期内该对象是唯一且恒定的。具有非重叠生存期的两个对象可能具有相同的id()值。

     

CPython实现细节:这是内存中对象的地址。

所以,我使用id()和列表进行了实验:

>>> list = [1,2,3]
>>> id(list[0])
31186196
>>> id(list[1])
31907092 // increased by 896
>>> id(list[2])
31907080 // decreased by 12

函数返回的整数是多少?它是C中内存地址的同义词吗?如果是这样,为什么整数不对应于数据类型的大小?

在实践中何时使用id()

13 个答案:

答案 0 :(得分:136)

您的帖子提出了几个问题:

  

该功能返回的号码是多少?

一个整数(或长整数),保证在此生命周期内对该对象唯一且常量。(Python Standard Library - Built-in Functions)一个唯一的数字。没有更多,也没有更少。可以将其视为Python对象的社会安全号码或员工ID号。

  

C中的内存地址是否相同?

从概念上讲,是的,因为在他们的一生中,他们都保证在他们的宇宙中是独一无二的。在Python的一个特定实现中,它实际上是相应C对象的内存地址。

  

如果是,为什么数字不会立即增加数据类型的大小(我假设它会是int)?

因为列表不是数组,列表元素是引用,而不是对象。

  

我们何时才真正使用id( )功能?

几乎没有。 id()运算符中使用is(或其等价物)。

答案 1 :(得分:48)

这是内存中对象的位置的标识......

此示例可能会帮助您更多地理解这个概念。

foo = 1
bar = foo
baz = bar
fii = 1

print id(foo)
print id(bar)
print id(baz)
print id(fii)

> 1532352
> 1532352
> 1532352
> 1532352

这些都指向内存中的相同位置,这就是它们的值相同的原因。在示例中,1仅存储一次,而指向1的任何其他内容都将引用该内存位置。

答案 2 :(得分:8)

id()确实返回被引用对象的地址(在CPython中),但是你的混淆来自python列表与C数组非常不同的事实。在python列表中,每个元素都是引用。所以你所做的与这个C代码更相似:

int *arr[3];
arr[0] = malloc(sizeof(int));
*arr[0] = 1;
arr[1] = malloc(sizeof(int));
*arr[1] = 2;
arr[2] = malloc(sizeof(int));
*arr[2] = 3;
printf("%p %p %p", arr[0], arr[1], arr[2]);

换句话说,您正在从参考中打印地址,而不是相对于列表存储位置的地址。

在我的情况下,我发现id()函数可以方便地创建不透明的句柄,以便在从C调用python时返回到C代码。这样,您可以轻松地使用字典查找来自其手柄的物体,它保证是独一无二的。

答案 3 :(得分:5)

我开始使用python,当我使用交互式shell来查看我的变量是否分配给同一个东西或者它们看起来是否相同时,我使用id。

每个值都是一个id,它是一个唯一的数字,与存储在计算机内存中的位置有关。

答案 4 :(得分:5)

如果你正在使用python 3.4.1,那么你会得到一个不同的答案。

list = [1,2,3]
id(list[0])
id(list[1])
id(list[2])

返回:

1705950792   
1705950808  # increased by 16   
1705950824  # increased by 16

整数-5256有一个常量id,并且多次查找它的id不会改变,不像之前或之后的所有其他数字,每次你找到它时都有不同的id 。 从-5256的数字的ID越来越高,相差16

id()函数返回的数字是存储在内存中的每个项目的唯一ID,与C中的内存位置类似。

答案 5 :(得分:4)

罗布的回答(上面投票最多)是正确的。我想补充一点,在某些情况下使用ID很有用,因为它允许比较对象并找到哪些对象引用你的对象。

后者通常可以帮助您调试奇怪的错误,其中可变对象作为参数传递给类,并被分配给类中的本地变量。改变这些对象会改变类中的变量。这体现在奇怪的行为中,多个事物同时发生变化。

最近我在Python / Tkinter应用程序中遇到了这个问题,在一个文本输入字段中编辑文本会改变我输入的文本:)

这是一个关于如何使用函数id()来跟踪这些引用的位置的示例。无论如何,这不是一个涵盖所有可能情况的解决方案,但你明白了。 ID再次在后台使用,用户看不到它们:

class democlass:
    classvar = 24

    def __init__(self, var):
        self.instancevar1 = var
        self.instancevar2 = 42

    def whoreferencesmylocalvars(self, fromwhere):
        return {__l__: {__g__
                    for __g__ in fromwhere
                        if not callable(__g__) and id(eval(__g__)) == id(getattr(self,__l__))
                    }
                for __l__ in dir(self)
                    if not callable(getattr(self, __l__)) and __l__[-1] != '_'
                }

    def whoreferencesthisclassinstance(self, fromwhere):
        return {__g__
                    for __g__ in fromwhere
                        if not callable(__g__) and id(eval(__g__)) == id(self)
                }

a = [1,2,3,4]
b = a
c = b
democlassinstance = democlass(a)
d = democlassinstance
e = d
f = democlassinstance.classvar
g = democlassinstance.instancevar2

print( 'My class instance is of', type(democlassinstance), 'type.')
print( 'My instance vars are referenced by:', democlassinstance.whoreferencesmylocalvars(globals()) )
print( 'My class instance is referenced by:', democlassinstance.whoreferencesthisclassinstance(globals()) )

输出:

My class instance is of <class '__main__.democlass'> type.
My instance vars are referenced by: {'instancevar2': {'g'}, 'classvar': {'f'}, 'instancevar1': {'a', 'c', 'b'}}
My class instance is referenced by: {'e', 'd', 'democlassinstance'}

变量名称中的下划线用于防止名称分类。函数使用“fromwhere”参数,以便您可以让他们知道从哪里开始搜索引用。此参数由一个列出给定命名空间中所有名称的函数填充。 Globals()就是这样一个功能。

答案 6 :(得分:2)

答案几乎没有。 ID主要在Python内部使用。

普通的Python程序员可能永远不需要在代码中使用id()

答案 7 :(得分:2)

它是内存中对象的地址,正如文档所说的那样。但是,它附加了元数据,存储元数据需要对象的属性和内存中的位置。因此,当您创建名为list的变量时,还会为列表及其元素创建元数据。

所以,除非你是语言中的绝对大师,否则你无法根据前一个元素确定列表中下一个元素的id,因为你不知道语言与元素一起分配的内容。

答案 8 :(得分:1)

is运算符使用它来检查两个对象是否相同(而不是相等)。从id()返回的实际值几乎从未用于任何事情,因为它实际上没有意义,而且它与平台有关。

答案 9 :(得分:1)

我有一个想法是在记录中使用id()的值 它的价格便宜而而且很短 在我的情况下,我使用龙卷风,id()希望有一个锚点来分组通过网络套接字分散和混合文件的消息。

答案 10 :(得分:0)

我有点迟了,我将谈论Python3。要了解id()是什么以及它(和Python)如何工作,请考虑下一个示例:

>>> x=1000
>>> y=1000
>>> id(x)==id(y)
False
>>> id(x)
4312240944
>>> id(y)
4312240912
>>> id(1000)
4312241104
>>> x=1000
>>> id(x)
4312241104
>>> y=1000
>>> id(y)
4312241200

您需要将右侧的所有内容都视为对象。每次进行分配时,您都会创建一个新对象,这意味着新的ID。在中间,您可以看到仅为函数id(1000)创建的“野生”对象。因此,生命周期仅适用于该行代码。如果您检查下一行-您会看到当我们创建新变量x时,它具有与该野生对象相同的ID。几乎就像内存地址一样。

答案 11 :(得分:0)

要小心(关于下面的答案)...这是真的,因为123在-5到256之间...

makeElement

答案 12 :(得分:-1)

从python 3开始,将id分配给一个值而不是一个变量。这意味着,如果您按以下方式创建两个函数,则三个ID都相同。

>>> def xyz():
...     q=123
...     print(id(q))
...
>>> def iop():
...     w=123
...     print(id(w))
>>> xyz()
1650376736
>>> iop()
1650376736
>>> id(123)
1650376736