2014-04-28 52 views
1

似乎python中的字符串和字符串的行爲基本上不同。當我一個字符串傳遞給它得到僅在局部函數的範圍修改的功能,但是當我做同樣的一個快譯通,它的範圍被修改超越功能:python中不一致的變量範圍

def change_str(s): 
    s += " qwe" 

def change_arr(a): 
    a[1] = "qwe" 

ss = "asd" 
change_str(ss) 
print ss 
# prints: 
# asd 

aa = {0:"asd"} 
change_arr(aa) 
print aa 
# prints: 
# {0: 'asd', 1: 'qwe'} 

是這種行爲是故意的,如果是的話,爲什麼?

+0

[Python函數參數範圍(字典與字符串)]可能的重複](http://stackoverflow.com/questions/2951112/python-function-argument-scope-dictionaries-v-strings) – devnull

+0

@devnull:雖然問題是相似的,我認爲這個問題有獨立的興趣,因爲'+ ='和'[] ='是可以在某些類型上完成的操作,而不是這些特定類型。另一個問題是將項目分配與裸名分配進行比較,該分配永遠不會改變。 – BrenBarn

回答

1

不要讓'賦值'操作符欺騙你。這就是每個功能的真實情況:

def change_str(s): 
    # operation has been split into 2 steps for clarity 
    t = s.__iadd__("qwe") # creates a new string object 
    s = t # as you know, without the `global` keyword, this `s` is local. 

def change_arr(a): 
    a.__setitem__(1, "qwe") 

正如你所看到的,只有其中一個函數實際上有一個賦值操作。 []=是(或相當於).__setitem__()的簡寫。

+0

謝謝。這對了解發生的事情最有用。 – mulllhausen

5

這是故意的行爲。字符串在Python中是不可變的,所以基本上所有的字符串操作都會返回一個新的字符串,並且由於函數不返回任何內容,所以看不到新字符串asd qwe。您可以更改本地範圍之外的可變容器的內容,而無需聲明它們是全局的。

你可以在python的官方文檔data model中閱讀更多關於可變類型的信息。

+0

很酷。有沒有辦法宣佈一個不可改變的字典? – mulllhausen

+0

@mulllhausen如果你這樣做,你不能添加任何東西。那是你要的嗎? – SethMMorton

+0

@mullhausen並不是真的,因爲這種方式打破了字典的目的。你不能添加項目。 – msvalkon

1

是的,這是故意的。每種類型都決定了操作員如何使用它。字典類型設置爲a[1] = "qwe"修改字典對象。這些更改將在任何引用該對象的代碼中看到。字符串類型設置爲s += "qwe"確實不是修改對象,但返回一個新的對象。因此,引用原始對象的其他代碼將不會看到任何更改。

這是一種速記方式,即字符串是不可變的,字典是可變的。然而,值得注意的是,「字典是可變的」不是行爲發生的全部原因。原因是項目分配(someDict[item] = val)是一個操作,可以有效地改變字典。