数据传递在编程语言中一般分为两类,包括 值传递(将原数据复制粘贴)与地址传递(将原数据的地址传输过去)。

首先,我们解释一下值传递与地址传递。

值传递:将一个变量的值赋给另一个变量时,是数值在两个变量间传递。
这样的好处是,两个变量在赋值后不再相互影响。

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是一门高级语言,他的数据传递灵活的,会自动根据数据的类型进行值传递或地址传递,从而有效地增加程序的效率。