在Python中,为什么[:]切片操作的行为不一致?
列表和字符串的行为有所不同。
对于列表,它给出一个副本列表对象,对于字符串,它给出相同的字符串对象。
我发现这令人困惑,违反直觉。有什么办法解释/证明这一点吗?
>>> s = "1234"
>>> s is (s[:2] + s[2:])
False
>>> s is s[:]
True
>>> lst = [1,2,3,4]
>>> lst is lst[:]
False
>>> lst is (lst[:2] + lst[2:])
False
我觉得这部分令人困惑。我希望它返回False
。
>>> s is s[:]
True
此外,我希望这两个返回相同的结果False
,但事实并非如此。
>>> s is (s[:2] + s[2:])
False
>>> s is s[:]
True
有什么想法吗?
答案 0 :(得分:3)
对于大多数内置类型,Python尝试确保切片的(浅)突变不会影响切片的对象。
对于列表,这需要一个副本,否则,对l[:]
进行突变会对l
进行突变。
对于字符串来说,字符串不支持突变,因此即使s[:]
也像“突变s
不会影响s[:] is s
”这样的语句是虚无的。无需进行复制,因此,为了节省时间和内存,该实现不需要复制。这是实现细节,而不是语言保证。复制实现完全正确。
(您可能会认为涉及内部实习,但是没有。该对象重用优化与内部实习完全无关。即使对于非内部实习的字符串也是如此。如果需要,您可以查看the implementation。 )
通常,如果您的程序曾经关心不可变对象的标识,则可能是您做错了什么。对象身份对于可变对象很重要,Python确保可变对象的身份是可预测的。对于不可变对象,对象标识的意义很小,并且Python应用了许多对象重用实现,这些实现打破了许多关于对象标识的乐观假设。
答案 1 :(得分:0)
短字符串是interned,因此一百万个“测试”实例不会占用一百万个字符串。这是安全的,因为Python的字符串是不可变的:如果两个字符串一次相等,则可以保证它们在整个生命周期中都相等。
这是用相同的内存对象表示短字符串的另一个示例:
>>> a = 'foo'
>>> b = 'foo'
>>> a is b
True