为什么Python的string和元组是不可变的?
我不确定为什么string和元组是不可变的。 使它们不可变的优点和缺点是什么?
一个是性能:知道一个string是不可改变的,因此在施工时很容易将其布置 – 固定和不变的存储要求。 这也是区分元组和列表的原因之一。 这也允许实现安全地重用string对象。 例如,CPython实现为单字符string使用预分配对象,并且通常返回不改变内容的string操作的原始string。
另一个是Python中的string被认为是数字的“元素”。 没有任何数量的活动会将值8更改为任何其他值,在Python中,没有任何活动会将string“八”改变为任何其他值。
http://effbot.org/pyfaq/why-are-python-strings-immutable.htm
设想一种叫做FakeMutablePython的语言,在这里你可以使用列表赋值等来改变string(比如mystr[0] = 'a'
)
a = "abc"
这将在内存地址0x1的内存中创build一个条目,其中包含“abc”,标识符a
指向它。
现在,说你做..
b = a
这将创build标识符b
并将其指向相同的内存地址0x1
现在,如果string是可变的,你改变b
:
b[0] = 'z'
这改变了存储在0x1到z
的string的第一个字节。由于标识符a
指向这里,因此该string也会改变,所以..
print a print b
..都会输出zbc
这可能会导致一些非常奇怪的意外行为。 字典键将是一个很好的例子:
mykey = 'abc' mydict = { mykey: 123, 'zbc': 321 } anotherstring = mykey anotherstring[0] = 'z'
现在在FakeMutablePython中,事情变得相当奇怪 – 你最初在字典中有两个键,“abc”和“zbc”。然后你改变“abc”string(通过标识符anotherstring)为“zbc”,所以字典两个键“zbc”和“zbc”…
一个解决这个问题的方法是,只要你给一个标识符指定一个string(或者用它作为一个字典键),它就把string复制到0x1到0x2。
这可以防止上述情况,但是如果你有一个需要200MB内存的string呢?
a = "really, really long string [...]" b = a
突然你的脚本占用400MB的内存? 这不是很好。
如果我们把它指向相同的内存地址,直到我们修改它呢? 复制写入 。 问题是,这可能是相当复杂的做..
这是不可变性的地方..而不是要求.replace()
方法从内存复制string到一个新的地址,然后修改它,并返回..我们只是使所有string不可变,因此该函数必须创build一个新的string返回。 这解释了下面的代码:
a = "abc" b = a.replace("a", "z")
并被certificate:
>>> a = 'abc' >>> b = a >>> id(a) == id(b) True >>> b = b.replace("a", "z") >>> id(a) == id(b) False
( id()
函数返回对象的内存地址)
使它们不变的一大优点是它们可以用作字典中的键。 我敢肯定,如果键被允许改变的话,字典使用的内部数据结构会变得相当混乱。
不可变types在概念上比可变types简单得多。 例如,你不必像C ++那样拷贝构造函数或者const正确性。 更多的types是不可变的,语言越容易。 因此,最简单的语言是没有任何全局状态的纯function语言(因为lambda微积分比图灵机更容易,同样强大),尽pipe很多人似乎并不欣赏这一点。
Perl有可变的string,似乎function正常。 以上看起来像是一个任意的devise决定挥手和合理化的手。
我回答了为什么Python有不变的string的问题,因为Python的创build者Guido van Rossum就是这么想的,现在他有很多的粉丝会为这个随意的决定辩护。
你可能会提出一个类似的问题,为什么Perl没有不可变的string,一大堆人会写出这个不可变string的概念是多么糟糕,为什么Perl是没有这个概念的Very Bestest Idea Ever(TM) 。
优点:性能
缺点:你不能改变mutables。