2009-10-08 30 views
46

我不確定爲什麼字符串和元組是不可變的;使它們不可變的優點和缺點是什麼?爲什麼Python字符串和元組是不可變的?

+1

除了python解釋器的內部實現之外,這個設計是否對編寫程序有很好的意義? (例如,如果元組和字符串是可變的,它會更容易嗎?) 如果是這樣,那麼選擇不可變元組和列表的例子是什麼? (或可能,可變字符串與python字符串) – user186477

+3

有一種稱爲函數編程的完整編程風格,其中一切都是不可變的。 http://en.wikipedia.org/wiki/Functional_programming –

+2

Python * DOES *具有可變的字符串和元組;它們分別拼寫爲'bytearray'和'list'。 – SingleNegationElimination

回答

31

一個是性能:知道一個 字符串是不可變的輕鬆 攤開來,在施工時間 - 固定不變的存儲 要求。這也是 元組和列表之間區別的原因之一。這也允許 實現安全地重用字符串 對象。例如,CPython 實現爲單字符字符串使用預分配的 對象, 並且通常返回原始 字符串用於字符串操作, 不會更改內容。

另一種是Python 中的字符串被認爲是「元素」,如 數字。 不會將數值8更改爲其他任何值, ,並且在Python中,任何數量的活動 都不會將字符串「八」更改爲 其他任何內容。

http://effbot.org/pyfaq/why-are-python-strings-immutable.htm

2

優點:性能

缺點:你不能改變mutables。

+6

優點:你不能改變他們 –

10

使它們不可變的一大優勢是它們可以用作字典中的鍵。我敢肯定,如果密鑰被允許改變,字典所使用的內部數據結構會變得相當混亂。

+3

Buuuuut你可以通過任何用戶創建的對象實例鍵入,這些實例顯然是可變的。那麼「key」可能只是內存地址,如果字符串是可變的,你仍然可以通過它們獨特的內存地址來鍵入。 – Triptych

+0

@Triptych這不會是你想要的字符串 - 你希望他們按價值鍵,否則字典將是沒有用的。 – Hejazzman

+0

@Hejazzman這不是如何python字典工作。字符串值不用作字典密鑰,而是使用字符串的散列值。用''abc'.__ hash __()'證明自己。 – Triptych

69

想象一個名叫FakeMutablePython,語言在這裏你可以使用列表賦值等(如mystr[0] = 'a')改變字符串

a = "abc" 

這造成在內存地址爲0x1存儲的條目,包括「ABC」,而指向它的標識符a

現在,說你做..

b = a 

這將創建標識b並且還指出爲0x1的相同的內存地址現在

,如果字符串是可變的,你改變b

b[0] = 'z' 

這改變儲存在爲0x1〜z字符串的第一個字節。由於該標識符a這裏指向到,因此該字符串也將改變,所以..

print a 
print b 

..would兩個輸出zbc

這可能使一些很奇怪的,意外的行爲。字典的鍵將是一個很好的例子:

mykey = 'abc' 
mydict = { 
    mykey: 123, 
    'zbc': 321 
} 

anotherstring = mykey 
anotherstring[0] = 'z' 
在FakeMutablePython

現在,事情變得相當奇怪 - 你最初在字典兩個按鍵,「ABC」和「ZBC」。然後你改變了「ABC 「字符串(通過標識符anotherstring)爲」zbc「,所以字典有兩個鍵,」zbc「和」zbc「... ...

這種奇怪的解決方案之一是,無論何時將字符串分配給標識符(或將其用作字典鍵),它將字符串0x1複製到0x2。

這可以防止上述情況,但如果您有需要200MB內存的字符串呢?

a = "really, really long string [...]" 
b = a 

突然你的腳本佔用了400MB的內存?這不是很好。

如果我們指向相同的內存地址,直到我們修改它,那麼呢? Copy on write。問題是,這可能是相當複雜的..

這是不變性進來..而不是要求.replace()方法將字符串從內存複製到一個新的地址,然後修改它,並返回..我們只是使所有的字符串不可變,因此函數必須創建一個新的字符串來返回。這就解釋了下面的代碼:

a = "abc" 
b = a.replace("a", "z") 

,並通過證明:

>>> a = 'abc' 
>>> b = a 
>>> id(a) == id(b) 
True 
>>> b = b.replace("a", "z") 
>>> id(a) == id(b) 
False 

(該id()函數返回對象的內存地址)

+2

+1最好的答案。真。 – wassimans

+1

我聽說過的最佳解釋! –

+0

所以如果我說a =「abc」,b =「abcd」它會共享abc嗎?像b [:4]是一個? – Dineshkumar

4

不變類型的概念比可變的要簡單。例如,你不必像C++那樣拷貝構造函數或者const正確性。更多的類型是不變的,語言越容易獲得。因此,最簡單的語言是沒有任何全局狀態的純功能語言(因爲lambda微積分比圖靈機更容易,同樣強大),儘管很多人似乎都不喜歡這樣。

3

Perl有可變字符串,似乎功能正常。對於任意的設計決策來說,上面的這些看起來像是很多的揮手和合理化。

我回答了爲什麼Python有不變字符串的問題,因爲Python的創建者Guido van Rossum就是這麼想的,現在他有很多粉絲會爲這個任意決定爲他們的死氣沉沉的捍衛。

你可能會提出一個類似的問題,爲什麼Perl沒有不可變的字符串,並且一大羣人會寫出不可變字符串的概念有多糟糕,爲什麼它是Perl不做的Very Bestest Idea Ever(TM)沒有他們。

+1

Perl並沒有真正的字符串:它具有標量,可以表現爲字符串或數字(多於一種類型)。如果標量是不可變的,那麼它將成爲純粹的功能Perl和Perl開發人員將通過將undef分配給自己來自殺。 –

相關問題