54

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

4

6 回答 6

84

Imagine a language called FakeMutablePython, where you can alter strings using list assignment and such (such as mystr[0] = 'a')

a = "abc"

That creates an entry in memory in memory address 0x1, containing "abc", and the identifier a pointing to it.

Now, say you do..

b = a

This creates the identifier b and also points it to the same memory address of 0x1

Now, if the string were mutable, and you change b:

b[0] = 'z'

This alters the first byte of the string stored at 0x1 to z.. Since the identifier a is pointing to here to, thus that string would altered also, so..

print a
print b

..would both output zbc

This could make for some really weird, unexpected behaviour. Dictionary keys would be a good example of this:

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

anotherstring = mykey
anotherstring[0] = 'z'

Now in FakeMutablePython, things become rather odd - you initially have two keys in the dictionary, "abc" and "zbc".. Then you alter the "abc" string (via the identifier anotherstring) to "zbc", so the dict has two keys, "zbc" and "zbc"...

One solution to this weirdness would be, whenever you assign a string to an identifier (or use it as a dict key), it copies the string at 0x1 to 0x2.

This prevents the above, but what if you have a string that requires 200MB of memory?

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

Suddenly your script takes up 400MB of memory? This isn't very good.

What about if we point it to the same memory address, until we modify it? Copy on write. The problem is, this can be quite complicated to do..

This is where immutability comes in.. Instead of requiring the .replace() method to copy the string from memory into a new address, then modify it and return.. We just make all strings immutable, and thus the function must create a new string to return. This explains the following code:

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

And is proven by:

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

(the id() function returns the memory address of the object)

于 2009-10-27T18:56:17.780 回答
34

一个是性能:知道字符串是不可变的,可以在构建时轻松布局——固定且不变的存储需求。这也是区分元组和列表的原因之一。这也允许实现安全地重用字符串对象。例如,CPython 实现对单字符串使用预先分配的对象,并且通常为不改变内容的字符串操作返回原始字符串。

另一个是 Python 中的字符串被视为数字的“元素”。任何活动都不会将值 8 更改为其他任何值,并且在 Python 中,任何活动都不会将字符串“8”更改为其他任何值。

https://web.archive.org/web/20201031092707/http://effbot.org/pyfaq/why-are-python-strings-immutable.htm

于 2009-10-08T15:51:29.473 回答
9

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

于 2009-10-08T15:52:09.537 回答
4

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

于 2010-07-02T12:16:34.777 回答
3

优点:性能

缺点:您不能更改可变变量。

于 2009-10-08T15:51:34.280 回答
3

Perl 具有可变字符串,并且似乎运行良好。对于任意的设计决策,上述内容似乎是大量的挥手和合理化。

我对为什么 Python 具有不可变字符串的问题的回答是,因为 Python 的创建者 Guido van Rossum 想要那样做,而且他现在拥有大批粉丝,他们会为这个任意决定辩护,直到他们垂死挣扎。

你可以提出一个类似的问题,为什么 Perl 没有不可变字符串,而一大群人会写出不可变字符串的概念是多么糟糕,以及为什么 Perl 没有它们是有史以来最好的想法 (TM) .

于 2012-05-31T15:54:11.563 回答