一、对象地址基础知识
python内置id()函数,这个函数用于返回对象的唯一标识(identity)。对象实际内存地址为hex(id(obj)),本文我将id()和内存地址划等号。
内置函数is(),用于比较两个对象的identity是否一样,举例:
(ob1 is ob2) 等价于 (id(ob1) == id(ob2))
a1 = '5'
print id(a1)
#输出:42662728,这个是a1指向的内存地址
a1 = '100'
a2 = '100'
print id(a1), id(a2)
#输出:43510440 43510440
#这里python做了优化,没有为a2申请新的内存,而且将a1和a2指向相同的内存地址
s1 = 'a' * 20
s2 = 'a' * 20
print id(s1), id(s2)
#输出:43997704 43997704,说明20个char情况下,python仍然将两个引用指向了相同内存地址
s1 = 'a' * 21
s2 = 'a' * 21
print id(s1), id(s2)
#输出:50071400 50071568,在21个char的时候,python就没有做优化了,python为s2开辟了新的内存
# int value
i1 = 10000000000000000000000..0000
i2 = 10000000000000000000000..0000
print id(i1), id(i2)
#输出:39278152 39278152,两个变量大约测试650位,内存地址仍然是一样的。linux下行为不太一样,值为256后,两变量指向内存就不一样了。
# float value
f1 = 250.5
f2 = 250.5
print id(f1), id(f2)
#输出:37976712 37976712,但在linux上两者的地址是不一样的
二、python的不可变(immutable)变量和可变变量
python不可变类型:int,string,float,tuple
#测试修改不可变变量
u = 100
print 'orgin id: %s' %id(u)
u = u + 10
print 'new id : %s' %id(u)
#输出:
#orgin id: 38833856
#new id : 38833616
#开始的时候u指向int值100内存地址,因为int对象是不可变的,所以后面u值改为110后其实是分配了一个新的内存地址
python可变类型:object、list、set等
#
a = []
print id(a)
a.append('a')
a.append('b')
a.append('c')
print id(a)
#输出:50809480,50809480,可见a指向内存的地址是没有改变的
三、方法参数传递
python参数传递是:传引用方式
def pass_immutable_var(v):
print 'inner before id:%d, value: %d' %(id(v),v)
v = 1000
print 'inner after id:%d, value: %d' %(id(v),v)
if __name__ == "__main__":
v = 100
print 'before id:%d, value: %d' %(id(v),v)
pass_immutable_var(v)
print 'after id:%d, value: %d' %(id(v),v)
输出:
before id:37785280, value: 100
inner before id:37785280, value: 100
inner after id:41170808, value: 1000
after id:37785280, value: 100
可见才方法里修改了参数int值是不会修改原int值的
def pass_obj_ref(v):
print 'inner before id:%d, value: %s' %(id(v),v)
v.append(999)
print 'inner after id:%d, value: %s' %(id(v),v)
if __name__ == "__main__":
v = ['100']
print 'before id:%d, value: %s' %(id(v),v)
pass_obj_ref(v)
print 'after id:%d, value: %s' %(id(v),v)
#输出:
before id:50203400, value: ['100']
inner before id:50203400, value: ['100']
inner after id:50203400, value: ['100', 999]
after id:50203400, value: ['100', 999]
可见在pass_obj_ref中拿到和之前一样的对象引用,是可以修改原对象的数据的。
这个示例有个值得注意的事情,如果pass_obj_ref内只将执行“v = []”,这个是不会导致原数据被修改的,因为这个操作只是使pass_obj_ref中的v指向的新的内存地址,而原对象指针仍然指向[‘100’],这里是个容易出问题的地方,需要严重注意。