Python中的引數遮蔽

orion發表於2022-02-02

我們有時會不經意間寫下如下程式碼:

def update_indices(indices):
    indices = [] # 像在更新indices前先將其置空
    for i in range(10):
        indices.append(i)

indices = [0, 1, 2]
update_indices(indices)
print(indices)

如上所示,我們有一個元素為indices的列表,想通過函式update_indices對其進行更新。不過有點特殊的是,我們想在update_indices中先將列表置空,然後再插入元素0, 1,..., 9。不過,程式碼執行的結果會出乎我們意料:

[0, 1, 2]

誒~並不是我們想象的[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],而是根本就沒有變,變數indices還是和呼叫函式update_indices前一樣。難道是因為函式引數傳的拷貝嗎?肯定不會,因為我們知道Python中對於列表統一傳的是引用,那是什麼導致我們對引數的修改失效了呢?
答案就是函式第一行的

indices = []

這一行看似是將函式引數indices置為空,其實是重新定義了一個函式中的區域性變數indices,這個區域性變數indices將函式的引數indices遮蔽掉了。而我們之後在函式中對indices的操作,其實都是在更改函式的區域性變數,當然不能影響到做為函式引數的indices了。

解決這個問題的途徑之一是:對於需要對引數重置的函式,我們最好直接傳返回值,避免引起歧義:

def update_indices():
    indices = [] # 像在更新indices前先將其置空
    for i in range(10):
        indices.append(i)
    return indices

indices = [0, 1, 2]
indices = update_indices()
print(indices)

這樣,結果就如我們預期了:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

相關文章