2009-10-08 27 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分配给自己来自杀。 –

相关问题