2.2 索引列表

正如我们已经看到的,Python 中的一个文本是一个单词的列表,用括号和引号的组合来表示。就像处理一页普通的文本,我们可以使用len(text1) 计算text1的词数,使用text1.count('heaven')计算一个文本中出现的特定的词,如'heaven'

稍微花些耐心,我们可以挑选出打印出来的文本中的第 1 个、第 173 个或第 14278 个词。类似的,我们也可以通过它在列表中出现的次序找出一个 Python 列表的元素。表示这个位置的数字叫做这个元素的索引。在文本名称后面的方括号里写下索引,Python 就会表示出文本中这个索引处如173的元素:

  1. >>> text4[173]
  2. 'awaken'
  3. >>>

我们也可以反过来做;找出一个词第一次出现的索引:

  1. >>> text4.index('awaken')
  2. 173
  3. >>>

索引是一种常见的用来获取文本中词汇的方式,或者更一般的,访问列表中的元素的方式。Python 也允许我们获取子列表,从大文本中任意抽取语言片段,术语叫做切片。

  1. >>> text5[16715:16735]
  2. ['U86', 'thats', 'why', 'something', 'like', 'gamefly', 'is', 'so', 'good',
  3. 'because', 'you', 'can', 'actually', 'play', 'a', 'full', 'game', 'without',
  4. 'buying', 'it']
  5. >>> text6[1600:1625]
  6. ['We', "'", 're', 'an', 'anarcho', '-', 'syndicalist', 'commune', '.', 'We',
  7. 'take', 'it', 'in', 'turns', 'to', 'act', 'as', 'a', 'sort', 'of', 'executive',
  8. 'officer', 'for', 'the', 'week']
  9. >>>

索引有一些微妙,我们将在一个构造的句子的帮助下探讨这些:

  1. >>> sent = ['word1', 'word2', 'word3', 'word4', 'word5',
  2. ... 'word6', 'word7', 'word8', 'word9', 'word10']
  3. >>> sent[0]
  4. 'word1'
  5. >>> sent[9]
  6. 'word10'
  7. >>>

请注意,索引从零开始:sent 第 0 个元素写作sent[0],是第一个单词'word1',而sent 的第 9 个元素是'word10'。原因很简单:Python 从计算机内存中的列表获取内容的时候,它已经位于第一个元素;我们要告诉它向前多少个元素。因此,向前 0 个元素使它留在第一个元素上。

注意

这种从零算起的做法刚开始接触会有些混乱,但这是现代编程语言普遍使用的。如果你已经掌握了 19XY 是 20 世纪中的一年这样的计数世纪的系统,或者如果你生活在一个建筑物楼层编号从 1 开始的国家,你很开就会掌握它的窍门,步行 n-1 级楼梯到第 n 层。

现在,如果我们不小心使用的索引过大就会得到一个错误:

  1. >>> sent[10]
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in ?
  4. IndexError: list index out of range
  5. >>>

这次不是一个语法错误,因为程序片段在语法上是正确的。相反,它是一个运行时错误,它会产生一个回溯消息显示错误的上下文、错误的名称:IndexError 以及简要的解释说明。

让我们再次使用构造的句子仔细看看切片。这里我们发现切片5:8 包含sent 中索引为 5,6 和 7 的元素:

  1. >>> sent[5:8]
  2. ['word6', 'word7', 'word8']
  3. >>> sent[5]
  4. 'word6'
  5. >>> sent[6]
  6. 'word7'
  7. >>> sent[7]
  8. 'word8'
  9. >>>

按照惯例,m:n 表示元素 m…n-1。正如下一个例子显示的那样,如果切片从列表第一个元素开始,我们可以省略第一个数字[1], 如果切片到列表最后一个元素处结尾,我们可以省略第二个数字 [2]

  1. >>> sent[:3] ![[1]](/projects/nlp-py-2e-zh/Images/4b5cae275c53c53ccc8f2f779acada3e.jpg)
  2. ['word1', 'word2', 'word3']
  3. >>> text2[141525:] ![[2]](/projects/nlp-py-2e-zh/Images/3a93e0258a010fdda935b4ee067411a5.jpg)
  4. ['among', 'the', 'merits', 'and', 'the', 'happiness', 'of', 'Elinor', 'and', 'Marianne',
  5. ',', 'let', 'it', 'not', 'be', 'ranked', 'as', 'the', 'least', 'considerable', ',',
  6. 'that', 'though', 'sisters', ',', 'and', 'living', 'almost', 'within', 'sight', 'of',
  7. 'each', 'other', ',', 'they', 'could', 'live', 'without', 'disagreement', 'between',
  8. 'themselves', ',', 'or', 'producing', 'coolness', 'between', 'their', 'husbands', '.',
  9. 'THE', 'END']
  10. >>>

我们可以通过赋值给它的索引值来修改列表中的元素。在接下来的例子中,我们把sent[0] 放在等号左侧[1]。我们也可以用新内容替换掉一整个片段[2]。最后一个尝试报错的原因是这个链表只有四个元素而要获取其后面的元素就产生了错误[3]

  1. >>> sent[0] = 'First' ![[1]](/projects/nlp-py-2e-zh/Images/4b5cae275c53c53ccc8f2f779acada3e.jpg)
  2. >>> sent[9] = 'Last'
  3. >>> len(sent)
  4. 10
  5. >>> sent[1:9] = ['Second', 'Third'] ![[2]](/projects/nlp-py-2e-zh/Images/3a93e0258a010fdda935b4ee067411a5.jpg)
  6. >>> sent
  7. ['First', 'Second', 'Third', 'Last']
  8. >>> sent[9] ![[3]](/projects/nlp-py-2e-zh/Images/334be383b5db7ffe3599cc03bc74bf9e.jpg)
  9. Traceback (most recent call last):
  10. File "<stdin>", line 1, in ?
  11. IndexError: list index out of range
  12. >>>

注意

轮到你来:花几分钟定义你自己的句子,使用前文中的方法修改个别词和词组(切片)。尝试本章结尾关于列表的练习,检验你是否理解。