Python學習之引數(一)
Python學習之引數(一)
引數的傳遞
所有的引數實際上都是通過指標進行傳遞的。作為引數被傳遞的物件從來不自動拷貝。
在函式內部的引數名的賦值不會影響呼叫者。
如果傳入的是可變物件,那麼在函式內就可以就地改變這個可變物件,這可能會影響呼叫者。
Python通過賦值進行傳遞的機制與C++的引用引數選項並不完全相同,實際上它與C語言的引數傳遞模型相當相似。
不可變引數“通過值”進行傳遞。像整數和字串這樣的物件是通過物件引用而不是拷貝進行傳遞的,但是因為你無論怎樣都不可能在原處改變不可變物件,所以實際效果就像建立了一份拷貝。
可變物件是通過指標進行傳遞的。例如,像列表和字典這樣的物件也是通過物件引用進行傳遞的,這一點與C語言使用指標傳遞陣列很相似:可變物件能夠在函式內部進行原處改變,這一點和C陣列很像。
以上只是偏重於理論的敘述,如果想搞清楚Python的引數傳遞機制,恐怕要研究幾個例子。
考慮如下程式碼:
>>> def f(a): # a is assigned to (references) the passed object
a = 99 # Changes local variable a only
>>> b = 88
>>> f(b) # a and b both reference same 88 initially
>>> print(b) # b is not changed
88
第3行,b引用了88,可以認為b指向了88;
第4行,呼叫函式f,把b傳了進去,實際上傳遞的是一個指標;
第1行,這裡的a擁有了b的值,實際上是a也指向88;
第2行,a又指向了99;
第5行,列印b,此時b已然指向88,所以結果是88。
我們們再看一個例子。
>>> def changer(a, b): # Arguments assigned references to objects
a = 2 # Changes local name's value only
b[0] = 'spam' # Changes shared object in place
>>> X = 1
>>> L = [1, 2] # Caller:
>>> changer(X, L) # Pass immutable and mutable objects
>>> X, L # X is unchanged, L is different!
(1, ['spam', 2])
從第8行的結果來看,X 並沒有改變,但是 L 從 [1, 2] 改變為 [‘spam’, 2]
X 沒有改變,這和第一個例子是同樣的道理。
我們分析一下 L 為什麼會改變。第1行的b也是一個本地變數,但是一個可變物件傳給了它——b指向了一個列表,它和L共享同一個物件。第3行,對b[0]進行賦值的結果會在函式返回後影響L的值。
下圖中說明了函式呼叫前和呼叫中變數名與物件的繫結關係。
在呼叫changer函式之前,X 指向 1,L 指向列表 [1, 2] ;在函式呼叫的時候,X的值(物件1的地址)被傳遞給 a,所以 a 也指向1,同理,b 指向列表 [1, 2] ;因為 1 是不可變物件,所以 a = 2 並不會修改物件 1,而是使 a 指向 2,但是列表是可變物件, b[0] = ‘spam’ 確實修改了列表 [1, 2] ,使其變成了 [‘spam’, 2]。
如果上面的內容依然令你困惑的話,你可以這麼理解,通過函式呼叫進行引數賦值與執行下面一系列簡單的賦值語句是等效的:
>>> X = 1
>>> a = X # They share the same object
>>> a = 2 # Resets 'a' only, 'X' is still 1
>>> print(X)
1
>>> L = [1, 2]
>>> b = L # They share the same object
>>> b[0] = 'spam' # In-place change: 'L' sees the change too
>>> print(L)
['spam', 2]
避免可變引數的修改
對可變引數的原處修改的行為不是一個 bug——它只是引數傳遞在Python中的工作方式。在Python中,預設通過引用(也就是指標)進行引數傳遞,因為這通常是我們想要的。這意味著不需要建立多個拷貝就可以傳遞很大的物件,並且能夠按照需要方便地更新這些物件。
如果不想要函式內部在原處的修改影響到傳遞給他的物件,那麼可以建立一個原物件的拷貝。例如:
L = [1, 2]
changer(X, L[:]) #通過切片傳遞拷貝,所以L不會改變
如果不想改變傳入的物件,無論函式是如何呼叫的,我們同樣可以在函式內部進行拷貝。
def changer(a, b):
b = b[:] # Copy input list so we don't impact caller
a = 2
b[0] = 'spam' # Changes our list copy only
—未完待續—
參考資料
《Python學習手冊(第4版)》,機械工業出版社
《Learning Python 5th Edition》, O’Reilly
相關文章
- 引數匹配模型——Python學習之引數(二)模型Python
- 引數匹配順序——Python學習之引數(三)Python
- python學習之數字Python
- Data Guard 學習之引數設定
- 記學習滲透測試之報告測試引數一
- golang學習之路之函式可變引數Golang函式
- python學習之變數型別Python變數型別
- Bootstrap Table 學習筆記之列引數(一)boot筆記
- 深入學習js之——引數按值傳遞#9JS
- Python學習之變數、物件和引用Python變數物件
- Python學習四之變數型別Python變數型別
- Shell學習【引數傳遞】
- oracle goldengate引數學習OracleGo
- java基礎的學習之引數的變化使用Java
- Swift學習筆記(三十三)——常量引數,變數引數和inout引數Swift筆記變數
- jmeter學習指南之引數化CSV Data Set ConfigJMeter
- 系統學習機器學習之半引數方法(二)--基於密度機器學習
- 滲透測試學習之報告測試引數五
- 【ASM學習】ASM引數說明ASM
- nofile引數的學習與整理
- Python學習之函數語言程式設計Python函數程式設計
- python函式之引數傳遞Python函式
- Python學習-變數Python變數
- Python學習筆記|Python之內建變數__name__Python筆記變數
- Python學習之模組Python
- Python之numpy學習Python
- python之pandas學習Python
- Python之Series 學習Python
- 12.MyBatis學習--對映檔案_引數處理_單個引數&多個引數&命名引數MyBatis
- 記學習滲透測試之報告測試引數二
- 記學習滲透測試之報告測試引數四
- 記學習滲透測試之報告測試引數三
- SpringMVC學習(三)對映請求引數&請求引數SpringMVC
- FAST_START_MTTR_TARGE 引數學習AST
- 【AIX 命令學習】lsvg 命令引數使用!AISVG
- 深度學習(模型引數直方圖)深度學習模型直方圖
- python基礎之 函式的引數Python函式
- python學習《一》Python