数据传递在编程语言中一般分为两类,包括 值传递(将原数据复制粘贴)与地址传递(将原数据的地址传输过去)。
首先,我们解释一下值传递与地址传递。
值传递:将一个变量的值赋给另一个变量时,是数值在两个变量间传递。
这样的好处是,两个变量在赋值后不再相互影响。
b=1
a=b
#a=1 b=1
b=2
#a=1 b=2
而地址传递则不同,当我们使用python传递list、dict等类型的变量时,由于这些变量普遍较大,完全复制不仅十分消耗内存而且运算速度也相对较慢,所以python内部采用的是地址传递(引用传递),通过传输变量的存储地址而对储存变量进行处理。
如何理解这一操作呢?
通俗来讲就是,小红搬到了新房子,小明想要直到小红的新房子长什么样子,于是他去问小刚:“小红的新房子长什么样子呢?”因为房子的结构与外观太复杂,小刚说不清,就给了小明一张纸条,上面写着小红新家的地址,于是,小明顺着地址找到了小红家,知道了小红新家的外观。但是如果别人来问,小明还是不能和别人完全解释小红新家的外观是什么样子的。只能继续给出地址,让下一个提问者根据地址,知晓房子的外观。
这就是对地址传递的通俗理解,list等类型的数据就是房子,因为造一栋完全相同的房子(也就是完全复制数据)太过浪费时间和空间,所以python中默认的办法就是传递这种大数据类的地址,从而方便快捷的传输内容。
a=[1,2,3,4]
b=a
#b=[1,2,3,4]
a.append(1)
#a=[1,2,3,4,1]
#b=[1,2,3,4,1]
当我们检查a、b的地址时
print('a的地址',id(a))
print('b的地址',id(b))
得到:a的地址:2508716715136 b的地址:2508716715136
二者的地址完全相同,这也证明了list数据的传递形式为地址传递。
当然,如果想要完全复制一个list类型的数据可以调用copy函数,如
b=a.copy()
调用后,会生成一个新的list变量,其数据内容与指定list变量相同。
什么决定了数据的传递方式?
一般,执行值传递或地址传递是由数据的类型决定的。
1、可变类型,值可以改变:
list列表
dict字典
np.array numpy矩阵
属于可变类型,添加或者修改数据时,变量对应的内存地址不会改变。
可变类型的修改一直在引用原来的内存地址。
注意,如果是重新赋值,内存地址就会发生改变。
而del 变量名 则只是删除一个指针,不删除变量。
2、不可变类型,值不可以改变:
数值类型int、long、bool、float
字符串str
元组tuple
属于不可变类型,一旦被重新赋值,变量对应的内存地址就会发生改变。
可变类型就可以进行地址传递,而不可变类型只能进行值传递。
两种传输方式的不同在函数调用时体现的更加明显
当我们在函数中传递单个数据时,采用的是值传递,若函数不加return进行返回,数据并不会发生改变。
def bfunction(b):
b=2
def b2function(b):
b=3
return b
b=0
a=bfunction(b)
#a=None 不返回内容
#b=0
a=b2function(b)
#a=3
#b=0
然而在函数调用list等数据类型时,并不需要特地设置return,数据也能正常更改并返回。
def afunction(a):
a.append(2)
a=[1,2,3,4]
afunction(a)
#a=[1, 2, 3, 4, 2]
总结:
python是一门高级语言,他的数据传递灵活的,会自动根据数据的类型进行值传递或地址传递,从而有效地增加程序的效率。