【问题标题】:How does python do list slices and modification on the LHS?python如何在LHS上列出切片和修改?
【发布时间】:2016-04-11 23:35:17
【问题描述】:

我知道 w 语法是如何工作的,但我想知道 python 如何替换和更改左侧列表的过程。 例如。

L = [0, 1, 2, 3, 4]
L[0:2] = [5]
print L #L is now [5, 2, 3, 4]

python 是怎么做的?

【问题讨论】:

    标签: python list python-2.7


    【解决方案1】:

    这是通过__setitem____setslice__ 方法完成的。 (__setslice__ 已弃用 IIRC 并在 python3.x 中删除)。

    对于列表,表达式:

    L[start: stop] = some_iterable
    

    将从some_iterable 获取项目并替换索引处的元素从开始到停止(不包括在内)。因此,在您的演示代码中,您有:

    L[0:2] = [5]
    

    这将获取索引01 处的元素并将它们替换为5

    请注意,替换列表的长度不必与要替换的子列表长度相同。

    也许更好的方式是将其视为执行以下操作的就地方式:

    L[a:b] = c
    
    # equivalent to the following operation (done in place)
    L[:a] + list(c) + L[b:]
    

    如果您真的对它如何感到好奇,源代码是最好的参考。 PyList_SetSlice 调用 list_ass_slice 将右侧的可迭代对象转换为序列(tuplelist IIRC)。它调整数组的大小以保存适当数量的数据,将切片右侧的内容复制到适当的位置,然后复制新数据。根据列表是增长还是缩小,有几种不同的代码路径(和操作顺序),但这是它的基本要点。

    【讨论】:

    • 非常感谢!
    【解决方案2】:

    在您的问题被标记的python 2.7 中,它是__setslice__ 魔术方法。详细信息记录在here in the datamodel section

    __setslice__(self, i, j, sequence)
        Called to implement assignment to self[i:j]. 
    

    这是一个用于向后兼容的旧接口。例如,如果您使用L[0:2:](应该是等效的)分配给一个切片,您实际上是通过__setitem__ 的新接口。

    要了解幕后发生的事情,您可以创建自己的类并继承一个列表:

    >>> class MyList(list):
    ...     def __setslice__(self, *args):
    ...         print '__setslice__ called with args:', args 
    ...         list.__setslice__(self, *args)
    ...     def __setitem__(self, *args):
    ...         print '__setitem__ called with args:', args        
    ...         list.__setitem__(self, *args)
    ...         
    

    我们来看几个例子:

    >>> L = MyList([0, 1, 2, 3, 4])
    >>> L[0:2] = [5]
    __setslice__ called with args: (0, 2, [5])
    

    传递的 3 个参数始终是左右端点,然后是赋值右侧的对象。

    >>> L[0:2:] = [5]
    __setitem__ called with args: (slice(0, 2, None), [5])
    

    使用带有步骤的切片将始终通过__setitem__ 的新接口,并传递slice 对象的实例而不是开始/停止索引。

    >>> L[1:] = [5]
    __setslice__ called with args: (1, 9223372036854775807, [5])
    

    省略端点使用sys.maxint(省略开始使用0)。

    >>> L[::] = 'potato'
    __setitem__ called with args: (slice(None, None, None), 'potato')
    

    右边的对象不一定是列表。

    我要提到的最后一件事是,如果您是从内置列表类型派生的,那么您只需要使用__setslice__。通常您想要这样做,如果您正在编写新代码,现代方式将是继承abstract base class,特别是collections.Sequence 是类列表结构的明显选择。这样,您就不必担心内置列表具有向后兼容性的所有缺陷和技巧。

    【讨论】:

      猜你喜欢
      • 2017-07-09
      • 2018-07-18
      • 2022-10-06
      • 1970-01-01
      • 2023-01-11
      • 1970-01-01
      • 2014-11-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多