Python引用、浅拷贝、深拷贝 和 Numpy中的视图、副本 和 Python函数参数传递

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

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值