我們知道C語言中只有值傳遞(地址也是值),C++中額外有引用傳遞,那麼在python中的參數是如何傳遞的呢,要理解這一點,我們就需要知道python傳遞的到底是什麼,在C/C++中有變量的概念,但是在python中是沒有這個概念的,在python的世界中,萬物皆對象
,我們可以通過名字
來操控這些對象,先來解釋以下這種思想:
>>>a = 1
>>>b = 1
>>>print(id(a))
1526188160
>>>print(id(b))
1526188160
>>> a = 'xxx'
>>> b = 'xxx'
>>> print(id(a))
66453024
>>> print(id(b))
66453024
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> print(id(a))
66536472
>>> print(id(b))
66552376
>>> a = (1, 2, 3)
>>> b = (1, 2, 3)
>>> print(id(b))
66372792
>>> print(id(a))
66372712
>>> a = {"a":1}
>>> b = {"a":1}
>>> print(id(a))
66565824
>>> print(id(b))
66570592
>>> b = (1, 2, 3)
>>> a = b
>>> print(id(a))
66372712
>>> print(id(b))
66372712
通過上面的測試,我們發現對於數值和字符串常量,只要值是相同的,那麼它們的名字的id就是相同的,但是對於列表,元組,字典等即使它們值是一樣,它們的id也是不同的,但如果是通過賦值操作,它們的id便是相同的,通過上面我們得出階段性結論:在Python中,萬物皆對象,通過名字操作對象,一個對象可以被多個名字關聯,一個名字只能關聯一個對象。
有了上面的理解,我們應該已經大概知道python中的參數傳遞是怎麼回事了,下面來具體解釋看一下
def function(args):
print(id(args))
a = []
function(a)
print(id(a))
PS C:\Users\jiage\Desktop\python\venv> python .\test.py
18892240
18892240
我們傳遞一個列表名字給函數,我們可以看到函數內部的名字args和外部的名字a指向同一個列表,下面我們試圖在函數內部改變這個列表內容。
def function(args):
a.append(2)
a = []
function(a)
print(a)
下面是執行結果
PS C:\Users\jiage\Desktop\python\venv> python .\test.py
[2]
可以看到,函數內部的操作影響到了外部的列表a,這說明,利用任何對象的任何一個標籤都可以改變對象的值(首先這個對象得是可變對象),上面的一切都符合我們的預期,但是下面有點不一樣。
下面我們傳遞一個數值對象進去看看
def function(args):
print(id(args))
a = 0
function(a)
print(id(a))
PS C:\Users\jiage\Desktop\python\venv> python .\test.py
1526188144
1526188144
彷彿也沒什麼問題,內部的名字args還是與a指向同一個對象,接着看
def function(args):
args = 1
print(id(args))
a = 0
function(a)
print(id(a))
print(a)
PS C:\Users\jiage\Desktop\python\venv> python .\test.py
1526188160
1526188144
0
我們發現,當給args賦值後,args就與a指向的對象不同了,按照我們前面的設想,這時候它們應該還是一樣的,而且a的值應該變成1,但這時候a卻沒有變,這是怎麼回事呢?經過調查,我發現,語言在設計之初就不希望常量對象被改變,所以我們是無法通過標籤來改變一個內存中的數值的,我們只能把這個標籤貼到另一個常量對象上,這與C/C++是不同的,C/C++是實實在在地通過指針改變了對應存儲單元的內容。
說到這裏,上面的現象也就不難理解了,當我們把a賦值給args後,如果我們沒有給args賦值,那麼我們可以照常引用a的值,但是一旦我們給args重新賦值之後,args就相當於從a指向的對象上撕了下來貼到了另一個新的對象上,所以它之後就和a完全沒有關係了。