python如何在LHS上列出切片和修改?

时间:2016-04-11 23:35:18

标签: python list python-2.7

我知道这个语法是如何工作的,但我想知道python如何替换并改变左侧列表的过程。 实施例

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

python如何解决这个问题?

2 个答案:

答案 0 :(得分:6)

这是通过__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)。它调整数组大小以保存适当数量的数据,将切片右侧的内容复制到适当的位置,然后复制新数据。根据列表是增长还是缩小,有一些不同的代码路径(和操作顺序),但这是它的基本要点。

答案 1 :(得分:3)

在你的问题被标记的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是列表的明显选择 - 像结构。这样您就不必担心内置列表具有向后兼容性的所有瑕疵和黑客。