用id函数做几个测试

2019年9月3日 / 9次阅读 / Last Modified 2019年9月4日
内置函数

Python内置的id函数其实非常简单,就是将参数对象的内存地址返回,即id函数返回的是一个很大的整数(地址)。基于Python语言的特性,本文做了几个测试,还比较有趣。

相同整数的id相同

>>> a = 6
>>> b = 6
>>> id(a)
94061989787808
>>> id(b)
94061989787808
>>> a == b
True
>>> a is b
True

a和b是两个变量,但是按照上面代码的显示,a和b不仅内容相同,地址也相同,a就是b。(==和is的区别

这是Python为了高效利用内存而采取的一种机制,a和b都是对一个内存中对象的引用,赋值(=)实际上是创建一个对象,将地址给引用变量。既然a和b指向的对象都是6这个整数,Python就没有“动力”去创建多个对象了。有人会问,如果修改变来领的值,比如修改a的值为7,b的值会跟着变吗?答案是不会。看下面的代码:

>>> a = 7
>>> a
7
>>> b
6
>>> id(a)
94061989787840
>>> id(b)
94061989787808
>>> a == b
False
>>> a is b
False

当 a=7 时,Python实际上是创建了一个新的值为7的整数对象,让a引用,同时保持6这个整数对象不变,这时,a和b的指向地址就不再相同了。

这是Python跟C很不一样的一个地方。在Python中,一切都是对象,所有变量都是对某个对象的应用(有点像指针),内存管理自动进行(某个对象的引用数为0的时候,自动清理这部分内存)。在C中,一切都是内存和指针,C编码在某种意义上是面向内存的编码,任何变量以及函数的返回值,都要明确定义类型,类型就是占用内存的大小。

相同整数的id不同

>>> i1 = 666666
>>> i2 = 666666
>>> i1 == i2
True
>>> i1 is i2
False
>>> id(i1)
140693768352752
>>> id(i2)
140693768353040

如果两个整数值比较大,id就不一样了。我也不明白为什么?数值小,id一样,数值大,id不一样。

相同浮点数的id不同

貌似浮点数,id总是不同的,这应该与浮点数的比较有关系(不能直接用==来比较浮点数)。

>>> f1 = 1.23
>>> f2 = 1.23
>>> f1 is f2
False
>>> f1 == f2  # not right to compare like this
True
>>> id(f1)
140693769437496
>>> id(f2)
140693769437304

返回函数局部变量

如上文所述,Python中所有的变量都是像C语言的指针一样,是一个指向对象的引用,Python在返回函数的局部变量的时候,返回的也是这个局部变量的引用地址。

>>> def test():
...     a = 12345
...     print(id(a))
...     return a
...
>>> b = test()
140693768353008  # id(a) in test()
>>> id(b)
140693768353008

test函数执行完毕后,将a的内存地址返回给了b。

这一个细节在一开始,还困扰了我一小会儿。函数的局部变量的地址处于调用栈内,在函数执行完成后,调用栈就会被弹出,局部变量的地址就失效了,不能在引用了。为什么Python不是这样呢?

Python确实没有为b重新创建一个新的对象,a对象对应的地址被传给了b,但是a这个变量也随着test函数执行完毕而消失了(a被弹出了调用栈,而不是a指向的内存对象被弹出,这段内存可理解在heap中)。Python中的变量,像指针,但却不是指针,只是对象的引用。a的有效范围在test函数内,test函数执行完后,a就不复存在,b获取了test函数的“返回值”,我们没有必要纠结b的内存地址是否与局部变量a一样。Python自己管理内存,我们编程者不需要太关心。a不能再使用了,但是a指向的内存对象还可以继续被使用,这并没有违背函数调用栈的逻辑(a本身被弹出栈,a指向的内存对象还在别的地方存在着,只要还有引用)。

Python内置的id函数一般情况下,没有什么用于,主要用于调试等场景。

-- EOF --

本文链接:https://www.pynote.net/archives/1042

留言区

《用id函数做几个测试》有2条留言

电子邮件地址不会被公开。 必填项已用*标注

  • 麦新杰

    Python中的变量,只是一个引用,一个标签!这一点要始终意识到。 [回复]

  • 麦新杰

    python官方文档里有这些:http://docs.python.org/c-api/int.html#PyInt_FromLong: 它指出,当前实现整数的数组对象是在-5和256之间的,当你创建一个int在这个范围内你实际上只是返回一个引用现有的对象内存地址。如果不在这个范围,可以id不一样。 [回复]


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top