Python列表切片[-1:]和[-1]之间有什么区别吗?

4

我读过这样的代码片段:

s = self.buffer_file.readline()
if s[-1:] == "\n":
    return s

如果我这样做:

s = 'abc'
In [78]: id(s[-1:]), id(s[-1])
Out[78]: (140419827715248, 140419827715248)

In [79]: id(s[-1:]) is id(s[-1])
Out[79]: False

In [80]: id(s[-1:]) == id(s[-1])
Out[80]: True

我觉得这没道理,虽然ID号码一样,但是ID确实不同。所以它们之间有某些不同的原因。


1
比较id()结果的身份是没有意义的。 - Ignacio Vazquez-Abrams
3个回答

9
切片列表的结果是一个列表,这与切片字符串的结果不同。
x = [1, 2, 3]

print(x[-1])  # --> 3
print(x[-1:]) # --> [3]

第二个案例只是一个元素的列表,但它仍然是一个列表。
请注意,Python没有与str类型不同的char类型,这意味着在str对象上进行元素访问和切片都会返回另一个str对象。
print("abcd"[-1])  # --> "d"
print("abcd"[-1:]) # --> "d"

使用字符串的切片表达式 s[-1:]s[:1] 而不是 s[-1]s[0] 的唯一优点是,当对空字符串进行操作时,切片表达式不会引发运行时错误(这是元素访问所做不到的)... 这可能会简化代码:
if len(s) > 0 and s[0] == '*': ...
if s[:1] == '*': ...

@liaozd: 请查看关于字符串切片的编辑。Python 没有 char 类型,因此对字符串进行元素访问和切片操作都会返回一个字符串。 - 6502

7
< p >使用s[-1:]而不是s[-1]的主要实际好处是前者会产生一个空可迭代对象,而不是停止并显示回溯信息。
>>> 'hi'[-1:]
'i'
>>> 'hi'[-1]
'i'
>>> ''[-1:]
''
>>> ''[-1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

这使得 if s[-1:] == "\n": 可以处理一个空行 s,而不需要在其之前添加 if s:。当 s 为空时,它将简单地计算为 False,而不会生成需要使用 try..except 结构来处理的错误。

5
"

id(s[-1:]) is id(s[-1])的意思是,这些id本身(整数)是引用相等的。假设使用CPython 2。

这个问题可能会依赖于具体的实现。

请注意小整数池。http://davejingtian.org/2014/12/11/python-internals-integer-object-pool-pyintobject/

这可能会有所帮助:

"
Python 2.7.10 (default, Sep 23 2015, 04:34:21)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.72)] on darwin

>>> s = 'abc'
>>> s[-1:]
'c'
>>> s[-1]
'c'
>>> s[-1:]
'c'
>>> a = s[-1:]
>>> b = s[-1]
>>> id(a)
4531751912
>>> id(b)
4531751912
>>> a is b
True
>>> id(a) is id(b)
False

对象ab是同一个对象,但它们的id是两个不“引用相等”的int

关于整数:

>>> 5 is 100
False
>>> 5 is 5
True
>>> 10000 is 10000
True
>>> 1000000000 is 1000000000
True
>>> a = 10000000
>>> a is 10000000
False
>>> a, b = 100000000, 100000000
>>> a is b
True
>>> a is 100000000
False
>>> id(100000000)
140715808080880
>>> id(a)
140715808080664
>>> id(b)
140715808080664
>>> id(100000000)
140715808080640
>>>

进一步阅读: 有关此事的PyPy实现细节:http://doc.pypy.org/en/latest/cpython_differences.html#object-identity-of-primitive-values-is-and-id

如果我执行 a, b = 1, 1,那么 a is b 返回 True - oliverpool
字符串有点特殊——它们的“元素”也是字符串。这就是为什么你会得到相同的id值,即ab。如果是列表,你不会得到这样的结果,因为a将是一个(单元素)列表,而b将是列表中的一个值(正如@6502在他们的答案中所说)。 - Snild Dolkow
@oliverpool 看起来同一行中的相同数字共享相同的ID。 - jiegec
@jiegec 如果我将其拆分为多行,它仍然保持 a = 1b = 2c = 1,使得 a is c 返回 True - oliverpool
2
@oliverpool 别忘了 Python 有一个适用于小数字的池。你必须测试大数字。 - jiegec
@jiegec,就是这样:谢谢,我其实不知道这个!而且这可能是问题的真正答案!!! - oliverpool

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接