Python 此代码中列表[:]的含义是什么?
这段代码来自Python的文档。我有点困惑Python 此代码中列表[:]的含义是什么?,python,list,for-loop,iteration,Python,List,For Loop,Iteration,这段代码来自Python的文档。我有点困惑 words = ['cat', 'window', 'defenestrate'] for w in words[:]: if len(w) > 6: words.insert(0, w) print(words) 以下是我最初的想法: words = ['cat', 'window', 'defenestrate'] for w in words: if len(w) > 6: words
words = ['cat', 'window', 'defenestrate']
for w in words[:]:
if len(w) > 6:
words.insert(0, w)
print(words)
以下是我最初的想法:
words = ['cat', 'window', 'defenestrate']
for w in words:
if len(w) > 6:
words.insert(0, w)
print(words)
为什么这段代码创建了一个无限循环而第一个没有呢?这是一个陷阱!对于python来说,这可以逃避初学者
words[:]
是这里的神奇酱汁
注意:
>>> words = ['cat', 'window', 'defenestrate']
>>> words2 = words[:]
>>> words2.insert(0, 'hello')
>>> words2
['hello', 'cat', 'window', 'defenestrate']
>>> words
['cat', 'window', 'defenestrate']
现在没有了[:]
:
>>> words = ['cat', 'window', 'defenestrate']
>>> words2 = words
>>> words2.insert(0, 'hello')
>>> words2
['hello', 'cat', 'window', 'defenestrate']
>>> words
['hello', 'cat', 'window', 'defenestrate']
这里需要注意的主要问题是words[:]
返回现有列表的副本
,因此您正在迭代一个未修改的副本
您可以使用id()
检查是否引用了相同的列表:
在第一种情况下:
>>> words2 = words[:]
>>> id(words2)
4360026736
>>> id(words)
4360188992
>>> words2 is words
False
for w in words[:]
在第二种情况下:
>>> id(words2)
4360188992
>>> id(words)
4360188992
>>> words2 is words
True
words = ['cat', 'window', 'defenestrate']
for w in words:
if len(w) > 6:
words.insert(0, w)
print(words)
值得注意的是,[i:j]
被称为切片操作符,它所做的是返回列表的一个新副本,从索引i
,一直到(但不包括)索引j
所以,单词[0:2]
给你
>>> words[0:2]
['hello', 'cat']
省略起始索引意味着它默认为0
,而省略最后一个索引意味着它默认为len(words)
,最终结果是您收到整个列表的副本
如果您想让代码更具可读性,我建议使用
copy
模块
from copy import copy
words = ['cat', 'window', 'defenestrate']
for w in copy(words):
if len(w) > 6:
words.insert(0, w)
print(words)
这与您的第一个代码片段基本相同,并且可读性更高
或者(正如DSM在评论中提到的)在python>=3上,您也可以使用words.copy()
,它做同样的事情 (除了@Coldspeed answer)
请看以下示例:
words = ['cat', 'window', 'defenestrate']
words2 = words
words2 is words
结果:True
它意味着名称word
和words2
指的是同一个对象
words = ['cat', 'window', 'defenestrate']
words2 = words[:]
words2 is words
结果:False
在本例中,我们创建了新对象。
words[:]
将words
中的所有元素复制到一个新列表中。因此,当您迭代words[:]
时,实际上是在迭代words
当前拥有的所有元素。因此,当您修改单词时,这些修改的效果在单词[:]
中不可见(因为您在开始修改单词之前调用了单词[:]
)
在后一个示例中,您正在迭代单词
,这意味着您对单词
所做的任何更改都确实对迭代器可见。因此,当您在单词
的索引0中插入时,您会将单词
中的每个其他元素“增加”一个索引。因此,当您继续进行for循环的下一次迭代时,您将在words
的下一个索引处获得元素,但这正是您刚才看到的元素(因为您在列表的开头插入了一个元素,将所有其他元素上移了一个索引)
要查看此操作,请尝试以下代码:
words = ['cat', 'window', 'defenestrate']
for w in words:
print("The list is:", words)
print("I am looking at this word:", w)
if len(w) > 6:
print("inserting", w)
words.insert(0, w)
print("the list now looks like this:", words)
print(words)
让我们看看迭代器和iterables:
iterable是具有返回
迭代器,或它定义了一个可以
从零开始的顺序索引(当
索引不再有效)。所以iterable是一个对象
可以从中获取迭代器
迭代器是具有next
(Python2)或\uuuuuuuuuuu
(Python3)方法的对象
iter(iterable)
返回迭代器对象,list\u obj[:]
返回一个新的list对象,即list\u对象的精确副本
在第一种情况下:
>>> words2 = words[:]
>>> id(words2)
4360026736
>>> id(words)
4360188992
>>> words2 is words
False
for w in words[:]
for
循环将迭代列表的新副本,而不是原始单词。单词的任何更改对循环迭代没有影响,循环正常终止
以下是循环的工作方式:
循环调用iterable上的iter
方法并在迭代器上迭代
循环调用迭代器对象上的next
方法,以从迭代器中获取下一项。重复此步骤,直到没有其他元素
当引发StopIteration
异常时,循环终止
在第二种情况下:
>>> id(words2)
4360188992
>>> id(words)
4360188992
>>> words2 is words
True
words = ['cat', 'window', 'defenestrate']
for w in words:
if len(w) > 6:
words.insert(0, w)
print(words)
您正在对原始列表单词进行迭代,并向单词添加元素对迭代器对象有直接影响。因此,每次更新单词时,相应的迭代器对象也会更新,从而创建一个无限循环
看看这个:
>>> l = [2, 4, 6, 8]
>>> i = iter(l) # returns list_iterator object which has next method
>>> next(i)
2
>>> next(i)
4
>>> l.insert(2, 'A')
>>> next(i)
'A'
每次在StopIteration
之前更新原始列表时,您都会得到更新的迭代器,next
会相应地返回。这就是循环无限运行的原因
有关迭代和迭代协议的更多信息,您可以查看。coz,您在每次迭代时都要在单词
列表中插入一个元素-)第一个元素是首字母单词
的副本,而不是单词
本身,您正在遍历在开始添加内容之前获取的单词的副本。在第二个示例中,您试图循环遍历单词
,同时使单词
变长,因此永远不会到达结尾。示例遍历数组的副本,而您的示例遍历列表本身。复制时,不会插入新词,因此它只循环3个值。您可以在那里添加更好的答案@cᴏʟᴅsᴘᴇᴇᴅ. FWIW,这里的简短回答确实解释了这个问题背后的原因。@Coldspeed当然-你可以把它写成words[:]=[w为w,如果len(w)>6][::-1]+words
…Jon,我提到过“更可读性”,而不是更少…:P@Coldspeed更具可读性:words[:0]=[w代表words中的w,如果len(w)>6]
。我建议强调使用is
而不是id()
,以查看您是否有不同的对象,因为当对象超出范围且