分配如何与列表切片一起使用?

Posted

技术标签:

【中文标题】分配如何与列表切片一起使用?【英文标题】:How does assignment work with list slices? 【发布时间】:2012-05-24 07:07:28 【问题描述】:

Python 文档说对列表进行切片会返回一个新列表。 现在,如果返回“新”列表,我有以下与“分配给切片”相关的问题

a = [1, 2, 3]
a[0:2] = [4, 5]
print a

现在的输出是:

[4, 5, 3] 
    返回的东西怎么会出现在表达式的左侧? 是的,我阅读了文档,它说这是可能的,既然切片列表返回一个“新”列表,为什么要修改原始列表?我无法理解其背后的机制。

【问题讨论】:

@Mark Longair 对不起,我认为只有代码应该被格式化而不是输出 见:6.2 Assignment statements 你知道a[0] = 4会做什么吗? @KartikAnand Slice assignment 是一种特殊情况,不会创建新列表。在= 的左侧创建一个没有名称绑定的对象是没有意义的,因此python 不会将其作为无效语法丢弃,而是将其变成更像您期望的东西。由于 python 没有引用,所以让切片的结果更改原始列表是行不通的。你得到一个副本。如果您提供了有关您的应用程序的更多信息,我们可能能够更好地帮助您以“pythonic”的方式做事。 :) @Darthfett 我现在没有在开发任何应用程序,而是在开始动手之前自学 python :) 【参考方案1】:

您混淆了两个使用非常相似语法的不同操作:

1) 切片:

b = a[0:2]

这会复制a 的切片并将其分配给b

2) 切片赋值:

a[0:2] = b

替换a 的切片为b 的内容。

虽然语法相似(我想是设计使然!),但这是两种不同的操作。

【讨论】:

这就是我的疑问,在第二种情况下,为什么 a 的切片不是一个新列表?? @KartikAnand 因为不是。这不是语言指定的内容。 明确地说,“takes a slice of”真正的意思是“make a copy of a slice”,这就是部分混淆的来源。 @KartikAnand:基本上,是的。解释器知道哪个是哪个,并适当地处理它们。 @Dubslow:您可以使用itertools 模块来做到这一点。对于您的情况,请使用函数islice、start=1stop=None。这将避免任何副本并使用延迟评估(在您的情况下延迟访问原始列表)。【参考方案2】:

当您在 = 运算符的左侧指定 a 时,您使用的是 Python 的 普通赋值,它会将当前上下文中的名称 a 更改为指向新的价值。这不会更改 a 指向的先前值。

通过在= 运算符的左侧指定a[0:2],您就是在告诉Python 您要使用slice assignment。切片赋值是列表的一种特殊语法,您可以在其中插入、删除或替换列表中的内容:

插入

>>> a = [1, 2, 3]
>>> a[0:0] = [-3, -2, -1, 0]
>>> a
[-3, -2, -1, 0, 1, 2, 3]

删除

>>> a
[-3, -2, -1, 0, 1, 2, 3]
>>> a[2:4] = []
>>> a
[-3, -2, 1, 2, 3]

替换

>>> a
[-3, -2, 1, 2, 3]
>>> a[:] = [1, 2, 3]
>>> a
[1, 2, 3]

注意:

切片的长度可能与切片的长度不同 分配的序列,从而改变目标序列的长度,如果 目标序列允许它。 - source

切片分配提供与tuple unpacking 类似的功能。例如,a[0:1] = [4, 5] 等价于:

# Tuple Unpacking
a[0], a[1] = [4, 5]

通过元组解包,您可以修改非顺序列表:

>>> a
[4, 5, 3]
>>> a[-1], a[0] = [7, 3]
>>> a
[3, 5, 7]

但是,元组解包仅限于替换,因为您无法插入或删除元素。

在所有这些操作之前和之后,a 是完全相同的列表。 Python 只是提供了很好的语法糖来就地修改列表。

【讨论】:

相似但不相同,因为您可以在左侧和右侧拥有不等数量的元素。 @MarkRansom 这是一个很好的观点,我添加了更多信息以使这一点显而易见。 a[:] = some_list 是否等同于 a = some_list[:]a = some_list @jadkik94 两者都不是。 a[:] = some_lista 的每个元素设置为 some_list 的元素。做你提到的任何一个都会改变a 是什么。例如:a = [1, 2, 3]b = aa[:] = [4, 5, 6]a is b。如果最后一行更改了 a 的值,而不是改变它,则最后一行将为 False。 @CaseyKuball 在我们进行切片分配时,start: stop: step 的值是否应该始终为正?【参考方案3】:

我之前遇到过同样的问题,它与语言规范有关。根据assignment-statements,

    如果赋值的左侧是订阅,Python 将在该对象上调用__setitem__a[i] = x 等价于a.__setitem__(i, x)

    如果赋值的左边是 slice,Python 也会调用 __setitem__,但参数不同: a[1:4]=[1,2,3] 相当于 a.__setitem__(slice(1,4,None), [1,2,3])

这就是为什么 '=' 左侧的列表切片表现不同的原因。

【讨论】:

【参考方案4】:

通过在赋值操作的左侧切片,您可以指定要分配给哪些项目。

【讨论】:

【参考方案5】:

当您执行a[0:2] = [4,5] 时,您为=(切片a[0:2])的左侧分配了=[4,5] 右侧的值。

【讨论】:

以上是关于分配如何与列表切片一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

切片整个列表的切片赋值和直接赋值有啥区别?

当切片本身是张量流中的张量时如何进行切片分配

使用列表中的字符串进行切片分配

使用负索引调整大小的列表切片分配[重复]

Python 切片分配内存使用情况

如何将 redux-toolkit createSlice 与 React 类组件一起使用