1.Python引用、浅拷贝、深拷贝
引用:
在python中,对象赋值实际上是对象的引用。
当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用。
直接赋值相当于视图(numpy),没有copy到额外的空间中。
>>> t1 = tuple('furzoom')
>>> t2 = t1
>>> id(t1),id(t2)
(139792198303936, 139792198303936)
浅拷贝:
如果list中没有引用其它对象,那么浅拷贝【copy()和切片两种方法】就和深拷贝一样一样了。
#1.copy()在没有其他对象时,和深拷贝一样
a = [1, 2, 3]
b = a.copy()
b[0] = 333
print(b)
print(a)
>>[333, 2, 3]
>>[1, 2, 3]
#2.切片方法在没有其他对象情况下,和深拷贝一样
a = [1,2,3]
b = a[:]
b
>> [1, 2, 3]
b[0] = 0
a
>> [1, 2, 3]
b
>> [0, 2, 3]
浅拷贝有两种方式,一个是工厂方法copy(),另一个是通过切片操作。
#1.copy()
c = [1,3,[2,3]]
d = c.copy()
c
>> [1, 3, [2, 3]]
d
>> [1, 3, [2, 3]]
d[2][0] = 999
d[1] = 2
d
>> [1, 2, [999, 3]]
c
>> [1, 3, [999, 3]]
#2.切片操作
a = [1,3,[2,3]]
b = a[:]
b[2][0] =1999
b[1] = 2
b
>> [1, 2, [1999, 3]]
a
>> [1, 3, [1999, 3]]
附注:
#下面就是赋值操作了,也就是引用,一个变另一个也变
a = [1,3,[2,3]]
b = a
深拷贝
深复制,不仅复制对象本身,同时也复制该对象所引用的对象。
import copy
a = [1,2,3]
b =copy.deepcopy(a)
b
>> [1, 2, 3]
b[0] = 0
b
>> [0, 2, 3]
a
>> [1, 2, 3]
c = [1,2,[3,4]]
d = copy.deepcopy(c)
d
>> [1, 2, [3, 4]]
d[0] = 0
d[2][1] = 2
d
>> [0, 2, [3, 2]]
c
>> [1, 2, [3, 4]]
总结:
浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象。
深拷贝 拷贝对象及其子对象
2.Numpy中的视图、副本
数组切片返回的对象是原始数组的视图(视图=引用)。
Python的列表List切片得到的是副本(副本=浅拷贝)。
Numpy中的赋值(引用)、数组切片、copy()
#1.赋值/引用
a = np.array([1,2,3,4])
b = a
b
>> array([1,2,3,4])
a[2] = 0
b
>> array([1,2,0,4])
#2.数组切片(也就是视图/引用)
c = np.array([1,2,3,4])
d = c[:]
d[0] = 0
d
>> array([0, 2, 3, 4])
c
>> array([0, 2, 3, 4])
c[1] = 1
c
>> array([0, 1, 3, 4])
d
>> array([0, 1, 3, 4])
#3.copy()【类似列表中的deepcopy()】
import numpy as np
import copy
a = np.array([1,2,3,4])
c = a.copy()
c
>> array([1, 2, 3, 4])
c[0] = 0
c
>> array([0, 2, 3, 4])
a
>> array([1, 2, 3, 4])
3.Python函数参数传递(值传递还是引用传递)
Python值传递和引用传递区别,哪些类型值传递,哪些是引用传递?
值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参数的值。
a1 = 520
a2 = a1
print a1
>> 520
print a2
>> 520
a2 = a1 + 1
print a2
>>521
print a1
>>520
引用传递:也称地址传递,在方法调用时,实际上是把参数的引用(传的是地址,而不是参数的值)传递给方法中对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。
a1 = [1,2]
a2 = a1
a2.append(3)
print a1
>>[1, 2, 3]
print a2
>>[1, 2, 3]
在Python中,数字、字符或者元组等不可变对象类型都属于值传递,而字典dict或者列表list等可变对象类型属于引用传递。
如果要想修改新赋值后原对象不变,则需要用到python的copy模块,即对象拷贝。对象拷贝又包含浅拷贝和深拷贝。下面用例子来说明:
import copy
l1 = [[1, 2], 3]
l2 = copy.copy(l1)
l3 = copy.deepcopy(l1)
l2.append(4)
l2[0].append(5)
l3[0].append(6)
最后的结果:
l1 = [[1, 2, 5], 3]
l2 = [[1, 2, 5], 3, 4]
l3 = [[1, 2, 6], 3]
从上例可以看出,copy.copy属于浅拷贝,拷贝的是第一层list,而copy.deepcopy属于深拷贝,对list所有子元素都进行深拷贝。
参考文章:
http://blog.csdn.net/pipisorry/article/details/45830941
https://jingyan.baidu.com/article/5225f26bbaae00e6fa0908a3.html
http://blog.csdn.net/Dream_angel_Z/article/details/51496044