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


99

Python文档说切片列表会返回一个新列表。
现在,如果返回了“新”列表,我将对“分配给切片”存在以下疑问

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

现在的输出将是:

[4, 5, 3] 
  1. 返回内容的内容如何出现在表达式的左侧?
  2. 是的,我阅读了文档,并说有可能,因为切片列表会返回“新”列表,为什么要修改原始列表?我无法理解其背后的机制。

@马克Longair对不起,我以为只是代码应该被格式化不是输出
卡尔蒂克阿南德

2
请参阅:6.2赋值语句
约什-李

7
你知道a[0] = 4会做什么吗?
李乔(Josh Lee)

1
@KartikAnand Slice分配是一种特殊情况,其中不会创建新列表。在的左侧创建一个没有名称绑定的对象是没有意义的=,因此python不会将其视为无效的语法,而是将其转变为更像您期望的样子。由于python没有引用,因此无法使slice的结果更改原始列表。您会得到一份副本。如果您提供了有关应用程序的更多信息,我们也许可以更好地帮助您以“ pythonic”方式进行操作。:)
Casey Kuball

1
@Darthfett我现在不在任何应用程序上工作,而是在我开始弄脏手之前正在教自己python :)
Kartik Anand 2012年

Answers:


114

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

1)切片:

b = a[0:2]

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

2)切片分配:

a[0:2] = b

这会用的内容替换的切片。ab

尽管语法相似(我想是通过设计实现的!),但这是两个不同的操作。


4
这就是我的疑问,在第二种情况下,为什么不包括一个新列表呢?
卡蒂克·阿南德

11
@KartikAnand因为不是。这不是语言所指定的。
马钦(Marcin)2012年

明确地说,“切成薄片”实际上意味着“制作成薄片的副本”,这是造成混淆的部分原因。
马克·兰瑟姆

2
@KartikAnand:基本上是。解释器知道哪个是哪个,并适当地处理它们。
NPE 2012年

1
@Dubslow:您可以使用itertools模块来实现。为了您的情况下使用该功能islice,用start=1stop=None。这将避免任何复制并使用延迟评估(在您的情况下,延迟访问原始列表)。
Spiros

66

当您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]

注意:

切片的长度可以与分配序列的长度不同,从而在目标序列允许的情况下更改目标序列的长度。- 来源

切片分配提供类似于元组拆包的功能。例如,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只是提供了不错的语法糖来就地修改列表。


6
相似但不完全相同,因为左右元素的数量不相等。
马克·兰瑟姆

@MarkRansom这是一个很好的观点,我添加了更多信息以使这一点显而易见。
Casey Kuball 2012年

2
a[:] = some_list等同于a = some_list[:]a = some_list
jadkik94 2012年

2
@ jadkik94都不是。 a[:] = some_list将的每个元素都设置asome_list。做您提到的任何一个都会改变a。例如:a = [1, 2, 3] b = a a[:] = [4, 5, 6] a is b。如果更改了a的值,而不是对其进行了更改,则最后一行将为False 。
Casey Kuball 2012年

@Darthfett有趣的是,我发现另外的问题:)谢谢。
jadkik94 2012年

25

我之前碰到过同样的问题,它与语言规范有关。根据分配陈述

  1. 如果分配的左侧是subscription,则Python将调用__setitem__该对象。a[i] = x等价于a.__setitem__(i, x)

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

因此,“ =”左侧的列表切片的行为有所不同。


4

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.