Python字符串切片中哪个优先?索引还是步骤?

时间:2019-06-16 18:37:09

标签: python string slice

我阅读了有关Python字符串切片(Reverse string: string[::-1] works, but string[0::-1] and others don't)的帖子,但是仍然有一些疑问。哪个优先?它是开始/结束位置的一个或多个索引吗?还是一步?首先评估哪个?

我在Python中尝试了很少的东西,结果却不一致。参见下面的代码/示例。我已经将自己的分析放在方括号中,这可能是错误的,因此也请帮助我进行更正。

  1. txt="abcdef"

txt[::-1] 结果='fedcba' (此处优先选择该步骤,因为它为负数,所以它从最后一个索引(即5或-1)开始,一直持续到第一个字符'a')

  1. txt[0:0:-1] 结果='' (似乎索引首先被评估。因此从0开始但在0之前结束,这是不可能的,因此没有结果。甚至没有评估步骤。)

  2. txt[:0:-1] 结果='fedcb' (优先选择步骤,然后再考虑索引。因此,第一个索引变为纬度位置“ f”,直到到达“ a”之前的一个位置)

  3. txt[0::-1] 结果='a' (对此我感到很惊讶。这里似乎优先选择了起始索引。首先将索引0评估为'a',然后评估步骤'-1'。但是由于步骤'-而无法访问其他内容1',则不再打印任何字符)

5a。 txt[0:1] result ='a'(为什么?step的默认值为'1'。似乎首先评估起始索引,访问'a',打印然后停止)。

5b。 txt[0:1:1] 结果='a'(与5a相同)

5c。 txt[0:1:-1] 结果=”(为什么呢?将其与5a进行比较。似乎在5c中,首先对step求值,然后对起始索引进行评估。如果应该先对起始索引求值,则应至少打印出“ a”)。

  1. txt[0:-1:-1] 结果=”(我期望基于对起始索引的偏好而获得'a')

  2. txt[0::-1] result ='a'(现在将其与上面的示例6进行比较。为什么这次会有不同的结果?空白的结束索引等效于直到到达字符串的末尾,不是吗?)

  3. txt[:len(txt):-1] result =''(将其与6和7进行比较)

  4. txt[:0:-1] 结果='fedcb'(似乎优先考虑步骤,然后对表达式进行求值。基于步骤-1,将起始索引求值为最后一个位置'f')

所有这些至少让我感到困惑。

2 个答案:

答案 0 :(得分:3)

用于插槽的默认数字值(无论它们是空白还是None)都是

  1. 0,如果步数为负,则为len(x)-1
  2. len(x),如果步数为负,则为-len(x)-1
  3. 1

向后移动时,末尾插槽的一个奇怪的默认设置是取消添加len(x)作为负索引。

如果未指定步骤,则它的“优先级”仅在于其默认设置会影响其他两个步骤的默认设置。

提供所有值后,将切片定义为通过从起始值开始并在达到或超过终止值时停止(通过步骤的符号定义的“过去”)获得的许多元素(可能为0)

答案 1 :(得分:1)

from dis import dis
dis("txt[::-1]")

给我们

  1           0 LOAD_NAME                0 (txt)
              2 LOAD_CONST               0 (None)
              4 LOAD_CONST               0 (None)
              6 LOAD_CONST               2 (-1)
              8 BUILD_SLICE              3
             10 BINARY_SUBSCR
             12 RETURN_VALUE

因此我们可以看到开始和结束的默认值实际上是None。这意味着它们是在内部计算的,规则可能很复杂。但是,不是...

考虑以下(非常简单)的实现:

def impl(txt: str, start: int = None, end: int = None, step: int = 1):
    print("txt[{}:{}:{}] = ".format("" if start is None else start, "" if end is None else end, step), end="")
    # Handle the default values:
    if start is None:
        start = 0 if step >= 0 else len(txt) - 1
    elif start < 0:
        start = len(txt) + start
    if end is None:
        end = len(txt) if step >= 0 else -1
    elif end < 0:
        end = len(txt) + end

    def compare(index, end, step) -> bool:
        if step >= 0:
            return index < end
        if step < 0:
            return index > end

    # Compute the result
    result = ""
    index = start
    while compare(index, end, step):
        result += txt[index]
        index += step
    print(result)
    return result

将在所有情况下通过:

txt = "abcdef"
# 1.
assert (txt[::-1] == "fedcba" == impl(txt, None, None, -1))
# 2.
assert (txt[0:0:-1] == "" == impl(txt, 0, 0, -1))
# 3.
assert (txt[:0:-1] == "fedcb" == impl(txt, None, 0, -1))
# 4.
assert (txt[0::-1] == "a" == impl(txt, 0, None, -1))
# 5a
assert (txt[0:1] == "a" == impl(txt, 0, 1))
# 5b
assert (txt[0:1:1] == "a" == impl(txt, 0, 1, 1))
# 5c
assert (txt[0:1:-1] == "" == impl(txt, 0, 1, -1))
# 6.
assert (txt[0:-1:-1] == "" == impl(txt, 0, -1, -1))
# 7.
assert (txt[0::-1] == "a" == impl(txt, 0, None, -1))
# 8.
assert (txt[:len(txt):-1] == "" == impl(txt, None, len(txt), -1))
# 9.
assert (txt[:0:-1] == "fedcb" == impl(txt, None, 0, -1))
# Some others
assert (txt[::2] == "ace" == impl(txt, None, None, 2))    
assert (txt[::-2] == "fdb" == impl(txt, None, None, -2))
assert (txt[:-1:-2] == "" == impl(txt, None, -1, -2))
assert (txt[-2::-2] == "eca" == impl(txt, -2, None, -2))