我不确定为什么字符串和元组是不可变的;使它们不可变的优点和缺点是什么?
最佳答案
想象一种名为 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()
函数返回对象的内存地址)
关于python - 为什么 python 字符串和元组是不可变的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1538663/