为什么python字符串和元组是不可变的?

时间:2009-10-08 15:48:57

标签: python string immutability tuples

我不确定为什么字符串和元组是不可变的;使它们不可变的优点和缺点是什么?

6 个答案:

答案 0 :(得分:72)

想象一种名为FakeMutablePython的语言,您可以使用列表赋值等方式更改字符串(例如mystr[0] = 'a'

a = "abc"

在内存地址0x1中创建一个条目,包含“abc”,以及指向它的标识符a

现在,说你做..

b = a

这将创建标识符b,并将其指向相同的内存地址0x1

现在,如果字符串是可变的,并且您更改了b

b[0] = 'z'

这会将存储在0x1的字符串的第一个字节更改为z。由于标识符a指向此处,因此该字符串也会更改,因此..

print a
print b

..都会输出zbc

这可能会导致一些非常奇怪的意外行为。字典键就是一个很好的例子:

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

anotherstring = mykey
anotherstring[0] = 'z'

现在在FakeMutablePython中,事情变得相当奇怪 - 你最初在字典中有两个键,“abc”和“zbc”..然后你将“abc”字符串(通过标识符anotherstring)改为“ zbc“,所以dict有两个键,”zbc“和”zbc“......

这种奇怪的解决方案是,无论何时将字符串分配给标识符(或将其用作dict键),它都会将字符串复制为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()函数返回对象的内存地址)

答案 1 :(得分:31)

  

一个是表现:知道a   string是不可变的使得它很容易   在施工时间安排 -   固定和不变的存储   要求。这也是其中之一   区分的原因   元组和列表。这也允许   实现安全重用字符串   对象。例如,CPython   实施使用预先分配   单字符串的对象,   并且通常会返回原件   字符串操作的字符串   不会改变内容。

     

另一个是Python中的字符串   被视为“元素”   数字。没有多少活动   将值8更改为其他任何内容,   而在Python中,没有多少活动   将字符串“8”更改为   别的什么。

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

答案 2 :(得分:10)

使它们不可变的一大优点是它们可以用作字典中的键。我确信如果允许更改密钥,字典使用的内部数据结构会变得非常混乱。

答案 3 :(得分:4)

不可变类型在概念上比可变类型简单得多。例如,您不必像C ++中那样混淆复制构造函数或const正确性。更多类型是不可变的,语言越容易。因此,最简单的语言是没有任何全局状态的纯功能语言(因为lambda演算比图灵机更容易,同样强大),尽管很多人似乎并不欣赏这一点。

答案 4 :(得分:3)

专业人士:表现

缺点:你无法改变变异。

答案 5 :(得分:3)

Perl有可变字符串,似乎运行得很好。对于一个任意的设计决策来说,上面似乎有很多挥手和合理化。

我对Python为何具有不可变字符串的问题的答案,因为Python创建者Guido van Rossum希望这样,他现在拥有大批粉丝,可以捍卫他们垂死的气息。

你可能会提出一个类似的问题,为什么Perl没有不可变的字符串,而且一大堆人都会写出不可变字符串的概念是多么糟糕,以及为什么它是Perl没有的“非常最好的想法”(TM)有他们。