python中的id是否就是对象的python 内存地址址?

2010年5月 其他开发语言大版内专家分月排行榜第三2009年7月 其他开发语言大版内专家分月排行榜第三2005年3月 其他开发语言大版内专家分月排行榜第三
2012年1月 其他开发语言大版内专家分月排行榜第二2011年5月 其他开发语言大版内专家分月排行榜第二2010年12月 其他开发语言大版内专家分月排行榜第二2009年2月 其他开发语言大版内专家分月排行榜第二2008年9月 其他开发语言大版内专家分月排行榜第二2008年8月 其他开发语言大版内专家分月排行榜第二2008年5月 其他开发语言大版内专家分月排行榜第二2007年11月 其他开发语言大版内专家分月排行榜第二
2011年4月 其他开发语言大版内专家分月排行榜第三2011年1月 其他开发语言大版内专家分月排行榜第三2009年6月 其他开发语言大版内专家分月排行榜第三2009年4月 其他开发语言大版内专家分月排行榜第三2009年1月 其他开发语言大版内专家分月排行榜第三2008年11月 其他开发语言大版内专家分月排行榜第三2008年7月 其他开发语言大版内专家分月排行榜第三2008年6月 其他开发语言大版内专家分月排行榜第三2006年9月 其他开发语言大版内专家分月排行榜第三
2012年1月 其他开发语言大版内专家分月排行榜第二2011年5月 其他开发语言大版内专家分月排行榜第二2010年12月 其他开发语言大版内专家分月排行榜第二2009年2月 其他开发语言大版内专家分月排行榜第二2008年9月 其他开发语言大版内专家分月排行榜第二2008年8月 其他开发语言大版内专家分月排行榜第二2008年5月 其他开发语言大版内专家分月排行榜第二2007年11月 其他开发语言大版内专家分月排行榜第二
2011年4月 其他开发语言大版内专家分月排行榜第三2011年1月 其他开发语言大版内专家分月排行榜第三2009年6月 其他开发语言大版内专家分月排行榜第三2009年4月 其他开发语言大版内专家分月排行榜第三2009年1月 其他开发语言大版内专家分月排行榜第三2008年11月 其他开发语言大版内专家分月排行榜第三2008年7月 其他开发语言大版内专家分月排行榜第三2008年6月 其他开发语言大版内专家分月排行榜第三2006年9月 其他开发语言大版内专家分月排行榜第三
2010年6月 其他开发语言大版内专家分月排行榜第三2009年9月 C/C++大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。举例讲解Python中is和id的用法
作者:acmerfight
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了举例讲解Python中is和id的用法,是Python学习当中的基础知识,作者举例进行了简单说明,需要的朋友可以参考下
(ob1 is ob2) 等价于 (id(ob1) == id(ob2))
首先id函数可以获得对象的内存地址,如果两个对象的内存地址是一样的,那么这两个对象肯定是一个对象。和is是等价的。Python源代码为证。
static PyObject *
cmp_outcome(int op, register PyObject *v, register PyObject *w)
int res = 0;
switch (op) {
case PyCmp_IS:
res = (v == w);
case PyCmp_IS_NOT:
res = (v != w);
但是请看下边代码的这种情况怎么会出现呢?
In [1]: def bar(self, x):
return self.x + y
In [2]: class Foo(object):
def __init__(self ,x):
self.x = x
In [3]: foo = Foo(5)
In [4]: foo.bar is Foo.bar
Out[4]: False
In [5]: id(foo.bar) == id(Foo.bar)
Out[5]: True
两个对象用is判断是False,用id判断却是True,这与我们已知的事实不符啊,这种现象该如何解释呢?遇到这种情况最好的解决方法就是调用dis模块去看下两个比较语句到底做了什么。
In [7]: dis.dis("id(foo.bar) == id(Foo.bar)")
0 BUILD_MAP
3 BUILD_TUPLE
7 DELETE_GLOBAL
10 STORE_SLICE+1
11 SLICE+2
12 DELETE_SUBSCR
13 DELETE_SUBSCR
14 SLICE+2
15 BUILD_MAP
18 PRINT_EXPR
19 JUMP_IF_FALSE_OR_POP 11887
22 DELETE_GLOBAL
25 STORE_SLICE+1
In [8]: dis.dis("foo.bar is Foo.bar")
0 BUILD_TUPLE
4 DELETE_GLOBAL
8 BUILD_MAP
11 PRINT_EXPR
12 JUMP_IF_FALSE_OR_POP 11887
15 DELETE_GLOBAL
真实情况是当执行.操作符的时候,实际是生成了一个proxy对象,foo.bar is Foo.bar的时候,两个对象顺序生成,放在栈里相比较,由于地址不同肯定是False,但是id(foo.bar) == id(Foo.bar)的时候就不同了,首先生成foo.bar,然后计算foo.bar的地址,计算完之后foo.bar的地址之后,就没有任何对象指向foo.bar了,所以foo.bar对象就会被释放。然后生成Foo.bar对象,由于foo.bar和Foo.bar所占用的内存大小是一样的,所以又恰好重用了原先foo.bar的内存地址,所以id(foo.bar) == id(Foo.bar)的结果是True。
下面内容由邮件Leo Jay大牛提供,他解释的更加通透。
用id(expression a) == id(expression b)来判断两个表达式的结果是不是同一个对象的想法是有问题的。
foo.bar 这种形式叫 attribute reference [1],它是表达式的一种。foo是一个instance object,bar是一个方法,这个时候表达式foo.bar返回的结果叫method object [2]。根据文档:
&&& When an instance attribute is referenced that isn't a data attribute,
&&& its class is searched. If the name denotes a valid class attribute
&&& that is a function object, a method object is created by packing
&&& (pointers to) the instance object and the function object just found
&&& together in an abstract object: this is the method object.
foo.bar本身并不是简单的名字,而是表达式的计算结果,是一个 method object,在id(foo.bar)这样的表达式里,method object只是一个临时的中间变量而已,对临时的中间变量做id是没有意义的。
一个更明显的例子是,
print id(foo.bar) == id(foo.__init__)
输出的结果也是True
看 id 的文档[3]:
&&& 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 implementation detail: This is the address of the object in memory.
只有你能保证对象不会被销毁的前提下,你才能用 id 来比较两个对象。所以,如果你非要比的话,得这样写:
fb = foo.bar
Fb = Foo.bar
print id(fb) == id(Fb)
即把两个表达式的结果绑定到名字上,再来比是不是同一个对象,你才能得到正确的结果。
is表达式 [4] 也是一样的,你现在得到了正确的结果,完全是因为 CPython 现在的实现细节决定的。现在的is的实现,是左右两边的对象都计算出来,然后再比较这两个对象的地址是否一样。万一哪天改成了,先算左边,保存地址,把左边释放掉,再算右边,再比较的话,你的is的结果可能就错了。官方文档里也提到了这个问题 [5]。我认为正确的方法也是像id那样,先把左右两边都计算下来,并显式绑定到各自的名字上,然后再用is判断。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具  今天浏览博客的时候看到这么一句话: python中变量名和对象是分离的;最开始的时候是看到这句话的时候没有反应过来。决定具体搞清楚一下python中变量与对象之间的细节。(其实我感觉应该说 引用和对象分离 更为贴切)
  从最开始的变量开始思考:
   在python中,如果要使用一个变量,不需要提前进行声明,只需要在用的时候,给这个变量赋值即可 (这个和C语言等静态类型语言不同,和python为动态类型有关)。
   举第一个栗子:
    a = 1
   这是一个简单的赋值语句,整数 1 为一个对象,a 是一个引用,利用赋值语句,引用a指向了对象1;这边形象比喻一下:这个过程就相当于&放风筝&,变量a就是你手里面的&线&,python就跟那根&线&一样,通过引用来接触和拴住天空中的风筝&&对象。
   你可以通过python的内置函数 id() 来查看对象的身份(identity),这个所谓的身份其实就是 对象 的内存地址:
    注:
     python一切皆对象的理念,所以函数也是一个对象,因此可以使用 id() 函数的__doc__方法来查看这个函数的具体描述:
&&& id.__doc__
"id(object) -& integer\n\nReturn the identity of an object. This is guaranteed to be unique among\nsimultaneously existing objects.       (Hint: it's the object's memory address.)"
   第二个栗子:
    a = 2
    a = 'banana'
   利用上面第一个栗子用到的 id()函数:    
&&& a = 'banana'
    第一个语句中, 2是储存在内存中的一个整数对象,通过赋值 引用a 指向了 对象 1
    第二个语句中,内存中建立了一个字符串对象&banana&,通过赋值 将 引用a 指向了 &banana&,同时,对象1不在有引用指向它,它会被python的内存处理机制给当我垃圾回收,释放内存。
   第三个栗子:
    a = 3
    b = 3
   通过函数查看 变量a 和 变量b的引用情况: 
  在这里可以看到 &这俩个引用 指向了同一个 对象,这是为什么呢? 这个跟python的内存机制有关系,因为对于语言来说,频繁的进行对象的销毁和建立,特别浪费性能。所以在Python中,整数和短小的字符,Python都会缓存这些对象,以便重复使用。
   第四个栗子:
    1. &a = 4
    2. &b = a(这里就是让引用b指向引用a指向的那个对象)
    3. &a = a + 2
   通过函数查看引用情况:
    当执行到第2步的时候,查看一下 a 和 b 的引用:      
    可以看到 a 和 b 都指向了 整数对象 4
    接下来指向第3步:
&&& a = a+2
    可以看到 a 的引用改变了,但是 b 的引用未发生改变;a,b指向不同的对象; 第3句对 a 进行了重新赋值,让它指向了新的 对象6;即使是多个引用指向同一个对象,如果一个引用值发生变化,那么实际上是让这个引用指向一个新的引用,并不影响其他的引用的指向。从效果上看,就是各个引用各自独立,互不影响。
   第五个栗子(这个栗子会涉及到 python中的 可变数据类型 和 不可变数据类型):
   开始这个栗子之前,请记得注意到 第四个栗子的不同之处。
     1. & L1 = [1, 2, 3]
     2. & L2 = L1
     3. & L1[0] = 10
   通过函数查看引用情况:
     当执行第1步 和 第二步 的时候,查看一下 L1 和 L2 的引用情况:
&&& L1 = [1,2,3]
&&& L2 = L1
&&& id(L1)
&&& id(L2)
     此时 L1 和 L2 的引用相同,都是指向 [1,2,3]这个列表对象。
     接下来,继续执行第3步:
&&& L1[0] = 10
&&& id(L1)
&&& id(L2)
[10, 2, 3]
     同样的跟第四个栗子那样,修改了其中一个对象的值,但是可以发现 结果 并不与 第四个栗子那样, 在本次实验中,L1 和 L2 的引用没有发生任何变化,但是 列表对象[1,2,3] 的值 变成了 [10,2,3](列表对象改变了)
     在该情况下,我们不再对L1这一引用赋值,而是对L1所指向的表的元素赋值。结果是,L2也同时发生变化。
     原因何在呢?因为L1,L2的指向没有发生变化,依然指向那个表。表实际上是包含了多个引用的对象(每个引用是一个元素,比如L1[0],L1[1]..., 每个引用指向一个对象,比如1,2,3), 。而L1[0] = 10这一赋值操作,并不是改变L1的指向,而是对L1[0], 也就是表对象的一部份(一个元素),进行操作,所以所有指向该对象的引用都受到影响。
(与之形成对比的是,我们之前的赋值操作都没有对对象自身发生作用,只是改变引用指向。)
     列表可以通过引用其元素,改变对象自身(in-place change)。这种对象类型,称为可变数据对象(mutable object),词典也是这样的数据类型。
     而像之前的数字和字符串,不能改变对象本身,只能改变引用的指向,称为不可变数据对象(immutable object)。
     我们之前学的元组(tuple),尽管可以调用引用元素,但不可以赋值,因此不能改变对象自身,所以也算是immutable object.
        
    is关键字:
    当然,我们也可以要想知道是否指向同一个对象,我们可以使用 python的 is 关键词,is用于判断两个引用所指的对象是否相同。
    就像上述第四个栗子 当进行到 第1步 和 第2步 的时候:
&&& a is b
    当进行到第3步的时候:
&&& a = a + 2
&&& a is b
              
    突然想到,对于python 的 深拷贝 和 浅拷贝 的理解,也是可以根据这个进行验证,可以通过第五个栗子进行辅助理解。          
阅读(...) 评论()问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
下面是这个文章里面所演示的代码,
我有点费解的就是,按道理a和b完全就不是同一个变量,那么理论上他们无论值是什么,都应该是放在两个不同的内存空间啊,为什么他们相等的时候就放在了同一个内存空间呢?难道是python的运行时环境会自动判断他们的值,如果相同就放到同一个内存空间,为的是节省内存占用吗?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
Python实现int的时候有个小整数池。为了效率, Python首先在内心里创建出这些整数,然后复用了这部分整数,创建一个值为1的int,其实直接从这个池里拿出1。一般是-5到257。你弄个啥的看看。就不会这样了。看看这个:
分享到微博?
Hi,欢迎来到 SegmentFault 技术社区!⊙▽⊙ 在这里,你可以提出编程相关的疑惑,关注感兴趣的问题,对认可的回答投赞同票;大家会帮你解决编程的问题,和你探讨技术更新,为你的回答投上赞同票。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
扫扫下载 App}

我要回帖

更多关于 python 对象内存大小 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信