【问题标题】:How does reversing a string work with string[ : :-1]反转字符串如何与 string[ : :-1] 一起使用
【发布时间】:2020-06-12 04:45:21
【问题描述】:

我了解切片语法包含3个参数,即:

  1. 开始

  2. 停止

  3. 步骤

使用以下默认值:

  1. 开始 = 0

  2. stop = 字符串长度

  3. 步长 = 1

所以,对于

> string = "abc"

> string[::]

将返回

> "abc"

但是,对于

> string[::-1]

它不应该返回吗:

> "a"

因为,string[start = 0] = 'a' 然后,string[start + step],即string[0-1] = 'c',但是因为它不小于stop = 3,所以会中断。

或者我想错了方向,python 只是按照通常的方向切割字符串,如果步骤为负,则返回 that 字符串的反转?为简化起见,负步在内部是如何工作的?

【问题讨论】:

    标签: python string slice reverse


    【解决方案1】:

    当提供负步长值时,Python 会交换开始值和停止值。此外,当没有提供开始和结束值时,它们默认为序列的开始和结束。

    鉴于s[i:j:k],来自内置类型文档的the Common Sequence Operations section 的以下引用适用:

    如果 i 或 j 被省略或没有,它们将成为“结束”值(结束 取决于 k) 的符号。


    关于它是如何工作的,在 CPython 中有两个函数用于处理列表下标,list_subscript()(用于读取)和list_ass_subscript()(用于分配)。

    在这两个函数中,在验证下标指定切片后,调用PySlice_Unpack()PySlice_AdjustIndices() 以提取和规范化开始和停止值。

    开始值处理

    来自PySlice_Unpack()

    if (r->start == Py_None) {
        *start = *step < 0 ? PY_SSIZE_T_MAX : 0;
    

    如果起始值为None且步长值为负,则起始值设置为可能的最大值。

    然后,在PySlice_AdjustIndices()

    else if (*start >= length) {
        *start = (step < 0) ? length - 1 : length;
    

    如果起始值大于列表的长度(这无疑是由于上面的赋值)并且步长值为负,则起始值设置为length - 1(即length指序列的长度)。

    停止值处理

    来自PySlice_Unpack()

    if (r->stop == Py_None) {
        *stop = *step < 0 ? PY_SSIZE_T_MIN : PY_SSIZE_T_MAX;
    

    如果停止值为None且步长值为负,则停止值设置为可能的最小值。

    然后,在PySlice_AdjustIndices()

    if (*stop < 0) {
        *stop = (step < 0) ? -1 : 0;
    

    如果停止值是负数(这是由于上面的赋值)并且步长值是负数,停止值设置为-1。

    所以输入string[::-1],你最终会得到:

    • 起始值:len(string) - 1
    • 停止值:-1
    • 步骤:-1

    【讨论】:

    • 您链接到的 C 代码有点误导。这是del some_list[x:y:-z] 的代码,而不是用于获取切片。删除时,迭代的顺序无关紧要,因此代码会翻转参数。它不会在读取(或就地修改)切片的代码中执行此操作。查看the reading code 的几行或the modifying code 的几行。
    • 好电话。我在代码位置之间跳转时偏离了路线。鉴于读取/修改循环不关心步长值的符号,这一切都归结为开始和停止值的处理。 list_subscript()list_ass_subscript() 的切片处理部分都以调用 PySlice_Unpack()PySlice_AdjustIndices() 开始,这是开始/停止值处理的逻辑所在。
    • 又一次总结了 CPython 实现的相关部分。
    【解决方案2】:

    当负值作为step 传递时,startstop 的默认“值”相反。 start 从“序列开始”变为“序列结束”,stop 从“序列结束”变为“序列开始”。如果它不这样做,那么执行完整切片会出现问题,因为任何切片的结尾都是独占的; mystr[len(mystr)-1:0:-1] 将排除第一个字符(因为不会包括0),并且您不能通过-1 而不是过去0,因为这与len(mystr)-1 的含义相同(感谢 Python 处理负索引的方式),而且你什么都不会切掉。切换默认值,以便省略结尾(或等效地,显式传递None)一直运行到开头,包括在内,是唯一明智的解决方案。

    【讨论】:

    • 但是对于 s = "abc" 你说 s[::-1] 等价于 s[len(s) : 0 : -1]。那么由于 s[len(s)] 处没有任何内容,所以不应该出现该错误吗? *考虑到起点是包容的
    • @malibu:不。开始对应于序列的结束(即len(seq) - 1),而不是长度。而结尾根本没有数值;它实际上不能表示为空白或None 以外的任何内容(就像-1 如果-1 在Python 的索引/切片语义中不意味着len(seq)-1),因为结尾是排他性的(所以0将排除原始字符串的第一个字符)。因此,带有负步长的结尾可以被认为是“end is just past 0”(省略了刚刚过去的 0,因为 end 是排他的),但无法用数字来描述它。
    • @malibu:前向切片也有类似的问题,即将切片的结尾表示为值。如果你想阻止 i 字符的结尾,你可以使用 seq[:-i] unless i is 0 (这会导致你得到一个空序列,因为你什么都不切出去)。所以你要么一直做更昂贵的工作来切片到len(seq) - i,要么使用笨拙的seq[:-i] if i else seq[:],或者你get tricky
    猜你喜欢
    • 2019-06-18
    • 2013-09-12
    • 2016-04-24
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    • 2014-03-04
    • 1970-01-01
    相关资源
    最近更新 更多