版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/John_xyz/article/details/82190586
获取对象的地址
- id() 函数用于获取对象的内存地址。
>>>a = 'runoob'
>>> id(a)
4531887632
>>> b = 1
>>> id(b)
140588731085608
可变对象&不可变对象
- 在Python中,对象分为两种:可变对象和不可变对象,
不可变对象包括int,float,long,str,tuple等,可变对象包括list,set,dict等 - 需要注意的是:这里说的不可变指的是值的不可变。对于不可变类型的变量,如果要更改变量,则会创建一个新值,把变量绑定到新值上,而旧值如果没有被引用就等待垃圾回收。
- 可变类型数据对对象操作的时候,不需要再在其他地方申请内存,只需要在此对象后面连续申请(+/-)即可,也就是它的内存地址会保持不变,但区域会变长或者变短。
不可变对象示例
>>> a = 1
>>> id(a)
7068776
>>> b = a
>>> id(b)
7068776
>>> a += 1
# 重新赋值之后,变量a的内存地址已经变了
>>> id(a)
7068752
>>> a
2
>>> b
1
>>> id(b)
7068776
# 执行a=1后开辟了一块内存存放1,然后b也指向1,执行a+=1后,因为整型不可变,所以又开辟了一块内存存放2,现在a指向2,b还指向1。
可变对象示例
>>> a = [1,1]
>>> id(a)
140687424863480
>>> b = a
>>> id(b)
140687424863480
>>> a.append(3)
>>> b
[1, 1, 3]
>>> a
[1, 1, 3]
# 执行a = [1, 1]后,a指向这个列表,执行b = a后,b也指向这个列表,两个变量指向同一块内存。执行a.append(3)之后,因为列表是可变对象,append操作知识改变了其值,内存地址并没有变.
python中一切都是对象,参数传递都是对象的引用,具体的,如果函数收到的是可变对象(如列表字典),则可以修改对象的原始值;如果是不可变对象(整型浮点型字符元组),就不能修改原始对象。
函数传递参数
python的参数传递分为两种情况:
- 对于不可变对象作为函数参数,相当于C系语言的值传递
- 对于可变对象作为函数参数,相当于C系语言的引用传递
来看几个例子:
参数为不可变对象:
def add(num):
num = num + 10
d = 2
add(d)
print(d)
# 输出结果为2, 因为整数是不可变对象,执行num=num+10后,会产生新的对象,重新开辟一块内存存放12,num指向12, 而d没有变化
参数为可变对象
def add(nums):
nums.append(3)
d = [1,2]
add(d)
print(d)
# 输出结果为[1,2,3]。执行add方法时,nums指向[1,2]。因为列表是可变对象,直接在nums进行操作不会产生新的对象,所以返回[1,2,3]
赋值,浅拷贝,深拷贝的区别
- 直接赋值:其实就是对象的引用(别名)
- 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象
- 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。
b=a, 赋值引用,a和b都指向同一个对象
b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)
b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。
实例分析:
#!/usr/bin/python
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象
b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝
a.append(5) #修改对象a
a[4].append('c') #修改对象a中的['a', 'b']数组对象
print( 'a = ', a )
print( 'b = ', b )
print( 'c = ', c )
print( 'd = ', d )
'''输出结果
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
'''
总结如下:
- 普通的赋值得到的其实仅仅是共享引用
- 浅拷贝(字典的copy方法,list分片)可以进行顶层对象拷贝
- 深拷贝(copy.deepcopy)可以彻底实现自顶向下的完全拷贝