Python slice [:]行为不一致

时间:2019-01-24 23:46:25

标签: python python-3.x slice

在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

有什么想法吗?

2 个答案:

答案 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