Python 中 Id()函数是用来做什么的?

我读了 Python 2 的文档,注意到了 id()的功能:

Return the “identity” of an object. This is an integer (or long integer) which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

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

因此,我尝试使用 id()和一个列表:

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

What is the integer returned from the function? Is it synonymous to memory addresses in C? If so, why doesn't the integer correspond to the size of the data type?

id()在实践中什么时候使用?

111570 次浏览

这就是内存中物体的 位置的身份。

这个例子可以帮助您更好地理解这个概念。

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的任何其他内存都将引用该内存位置。

ID 主要在 Python 内部使用。

一般的 Python 程序员可能永远不需要在他们的代码中使用 id()

The is operator uses it to check whether two objects are identical (as opposed to equal). The actual value that is returned from id() is pretty much never used for anything because it doesn't really have a meaning, and it's platform-dependent.

id()确实返回被引用对象的地址(在 CPython 中) ,但是您的困惑来自于 python 列表与 C 数组非常不同的事实。在 python 列表中,每个元素都是 reference。所以你现在做的和这段 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]);

In other words, you are printing the address from the reference and 没有 an address relative to where your list is stored.

在我的例子中,我发现 id()函数可以方便地创建不透明句柄,在从 C 调用 python时返回到 C 代码。这样做,你可以很容易地使用字典从句柄中查找对象,并保证它是唯一的。

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

从函数返回的数字是什么?

它是“ 一个整数(或长整数) ,它保证在这个对象的生命周期内是唯一的和常数。(Python 标准库-内置函数)一个独一无二的数字。不多也不少。可以将其看作 Python 对象的社会安全号码或雇员 ID 号码。

C 语言中的内存地址也是这样吗?

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

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

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

我们什么时候真正使用 id( )函数?

几乎没有。您可以通过比较两个引用的 id 来测试它们是否相同,但是 is接线员一直是这样做的推荐方法。id( )只有在调试情况下才真正有用。

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

因此,除非你是这门语言的专家,否则你无法根据前一个元素来确定列表中下一个元素的 id,因为你不知道这门语言在分配元素的同时分配了什么。

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

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

如果您使用的是 python3.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 中的内存位置相同。

罗伯的答案(以上大部分投票)是正确的。我想补充的是,在某些情况下,使用 ID 是有用的,因为它可以比较对象并找到哪些对象引用您的对象。

后者通常可以帮助您调试奇怪的 bug,其中可变对象作为参数传递给类,并分配给类中的局部变量。对这些对象进行变异会使类中的 var 发生变异。这表现在奇怪的行为中,多个事物同时发生变化。

最近,我在 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'}

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

I have an idea to use value of id() in logging.
它很便宜,而且很短。
在我的情况下,我使用龙卷风和 id()希望有一个锚群消息散布和混合文件的网络套接字。

在 python3中,id 被赋给一个值而不是变量。这意味着如果像下面这样创建两个函数,所有三个 id 都是相同的。

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

我有点晚了,我要谈谈 Python 3。要理解 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。在中间,您可以看到一个只为 function-id (1000)创建的“ wild”对象。所以,它的生命周期只适用于这一行代码。如果你检查下一行-你会看到当我们创建新变量 x 时,它和那个通配对象有相同的 id。它的工作原理和内存地址差不多。

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

In [111]: q = 257


In [112]: id(q)
Out[112]: 140020248465168


In [113]: w = 257


In [114]: id(w)
Out[114]: 140020274622544


In [115]: id(257)
Out[115]: 140020274622768