我不确定为什么字符串和元组是不可变的;使它们不可变的优点和缺点是什么?
答案 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)有他们。