1 . 须知:
Python内置了多种序列,如列表(list)和元组(tuple),其实字符串(string)也是一种序列。
>>> "Hello,world!" >>> "Hello,world!"[0] 'H' >>>"Hello,world!"[-1] '!'
数据结构。数据结构是以某种方式(如通过编号)组合起来的数据元素(如数、字符乃至其他数据结构)集合。在Python中,最基本的数据结构为序列(sequence)。序列中的每个元素都有编号,即其位置或索引,其中第一个元素的索引为0,第二个元素的索引为1,依此类推。在有些编程语言中,从1开始给序列中的元素编号,但从0开始指出相对于序列开头的偏移量。这显得更自然,同时可回绕到序列末尾,用负索引表示序列末尾元素的位置。
注意 Python支持一种数据结构的基本概念,名为容器(container)。容器基本上就是可包含其他对象的对象。两种主要的容器是序列(如列表和元组)和映射(如字典)。在序列中,每个元素都有编号,而在映射中,每个元素都有名称(也叫键)。有一种既不是序列也不是映射的容器,它就是集合(set)。
2 . 列表是什么?
列表是由一系列按特定顺序排列的元素组成。你可以创建包括字母表中所有字母、数字0~9或所有家庭成员姓名的列表;也可以将任何东西加入列表中,其中的元素之间可以没有任何关系。鉴于列表通常包含多个元素,给列表指定一个表示复数的名称(如letters、digits或names)是个不错的主意。
在Python中,用方括号([])来表示列表,并用逗号来分隔其中的元素。
>>> strings['A','B','C'] >>> strings ['A','B','C']
3 . 通用的序列操作方法
有几种操作适用于所有序列,包括索引、切片、相加、相乘和成员资格检查。另外,Python还提供了一些内置函数,可用于确定序列的长度以及找出序列中最大和最小的元素。
索引:
序列中的所有元素都有编号——从0开始递增。你可像下面这样使用编号来访问各个元素:
>>> names = ["zhangsan","lisi"] >>> print(names[1]) lisi
索引(indexing)。你可使用索引来获取元素。这种索引方式适用于所有序列。当你使用负数索引时,Python将从右(即从最后一个元素)开始往左数,因此-1是最后一个元素的位置。
>>> names = ["zhangsan","lisi"] >>> print(names[-]) lisi
对于字符串字面量(以及其他的序列字面量),可直接对其执行索引操作,无需先将其赋给变量。这与先赋给变量再对变量执行索引操作的效果是一样的。
>>> ["zhangsan","lisi"] >>> ["zhangsan","lisi"][0] 'zhangsan'
如果函数调用返回一个序列,可直接对其执行索引操作。例如,如果你只想获取用户输入的年份的第4位,可像下面这样做:
>>> fourth = input('Year: ')[3] Year: 2005 >>> fourth '5'
切片:
除使用索引来访问单个元素外,还可使用切片(slicing)来访问特定范围内的元素。为此,可使用两个索引,并用冒号分隔:
>>> tag = '<a href="http://www.python.org">Python web site</a>' >>> tag[9:30] 'http://www.python.org' >>> tag[32:-4] 'Python web site'
如你所见,切片适用于提取序列的一部分,其中的编号非常重要:第一个索引是包含的第一个元素的编号,但第二个索引是切片后余下的第一个元素的编号。请看下面的示例:
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> numbers[3:6] [4, 5, 6] >>> numbers[0:1] [1]
简而言之,你提供两个索引来指定切片的边界,其中第一个索引指定的元素包含在切片内,但第二个索引指定的元素不包含在切片内。
简写:假设你要访问前述数字列表中的最后三个元素,显然可以明确地指定这一点。
>>> numbers[7:10]
[8, 9, 10]
在这里,索引10指的是第11个元素:它并不存在,但确实是到达最后一个元素后再前进一步所处的位置。明白了吗?如果要从列表末尾开始数,可使用负数索引。
>>> numbers[-3:-1]
[8, 9]
然而,这样好像无法包含最后一个元素。如果使用索引0,即到达列表末尾后再前进一步所处的位置,结果将如何呢?
>>> numbers[-3:0]
[]
结果并不是你想要的。事实上,执行切片操作时,如果第一个索引指定的元素位于第二个索引指定的元素后面(在这里,倒数第3个元素位于第1个元素后面),结果就为空序列。好在你能使用一种简写:如果切片结束于序列末尾,可省略第二个索引。
>>> numbers[-3:]
[8, 9, 10]
同样,如果切片始于序列开头,可省略第一个索引。
>>>> numbers[:3]
>[1, 2, 3]
实际上,要复制整个序列,可将两个索引都省略。
>>> numbers[:]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
更大的步长(切片):
执行切片操作时,你显式或隐式地指定起点和终点,但通常省略另一个参数,即步长。在普通切片中,步长为1。这意味着从一个元素移到下一个元素,因此切片包含起点和终点之间的所有元素。
>>> numbers[0:10:1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
在这个示例中,指定了另一个数。你可能猜到了,这显式地指定了步长。如果指定的步长大于1,将跳过一些元素。例如,步长为2时,将从起点和终点之间每隔一个元素提取一个元素。
>>> numbers[0:10:2] [1, 3, 5, 7, 9] numbers[3:6:3] [4]
显式地指定步长时,也可使用前述简写。例如,要从序列中每隔3个元素提取1个,只需提供步长4即可。
>>> numbers[::4]
[1, 5, 9]
当然,步长不能为0,否则无法向前移动,但可以为负数,即从右向左提取元素。
>>> numbers[8:3:-1] [9, 8, 7, 6, 5] >>> numbers[10:0:-2] [10, 8, 6, 4, 2]
>>> numbers[0:10:-2] [] >>> numbers[::-2] [10, 8, 6, 4, 2] >>> numbers[5::-2] [6, 4, 2] >>> numbers[:5:-2] [10, 8
在这种情况下,要正确地提取颇费思量。如你所见,第一个索引依然包含在内,而第二个索引不包含在内。步长为负数时,第一个索引必须比第二个索引大。可能有点令人迷惑的是,当你省略起始和结束索引时,Python竟然执行了正确的操作:步长为正数时,它从起点移到终点,而步长为负数时,它从终点移到起点。
序列相加:
可使用加法运算符来拼接序列。
>>> [1, 2, 3] + [4, 5, 6] [1, 2, 3, 4, 5, 6] >>> 'Hello,' + 'world!' 'Hello, world!' >>> [1, 2, 3] + 'world!' Traceback (innermost last): File "<pyshell>", line 1, in ? [1, 2, 3] + 'world!' TypeError: can only concatenate list (not "string") to list
从错误消息可知,不能拼接列表和字符串,虽然它们都是序列。一般而言,不能拼接不同类型的序列。
乘法:
将序列与数x相乘时,将重复这个序列x次来创建一个新序列:
>>> 'python' * 5 'pythonpythonpythonpythonpython' >>> [42] * 10 [42, 42, 42, 42, 42, 42, 42, 42, 42, 42]
None、空列表和初始化:
空列表是使用不包含任何内容的两个方括号([]
)表示的。如果要创建一个可包含10个元素的列表,但没有任何有用的内容,可像前面那样使用[42]*10
。但更准确的做法是使用[0]*10
,这将创建一个包含10个零的列表。然而,在有些情况下,你可能想使用表示“什么都没有”的值,如表示还没有在列表中添加任何内容。在这种情况下,可使用None
。在Python中,None
表示什么都没有。因此,要将列表的长度初始化为10,可像下面这样做:
>>> sequence = [None] * 10
>>> sequence
[None, None, None, None, None, None, None, None, None, None]
成员资格:
要检查特定的值是否包含在序列中,可使用运算符in
。这个运算符与前面讨论的运算符(如乘法或加法运算符)稍有不同。它检查是否满足指定的条件,并返回相应的值:满足时返回True
,不满足时返回False
。这样的运算符称为布尔运算符,而前述真值称为布尔值。
>>> permissions = 'rw' >>> 'w' in permissions True >>> 'x' in permissions False >>> users = ['mlh', 'foo', 'bar'] >>> input('Enter your user name: ') in users Enter your user name: mlh True >>> subject = '$$$ Get rich now!!! $$$' >>> '$$$' in subject True
长度、最小值和最大值:
内置函数len
、min
和max
很有用,其中函数len
返回序列包含的元素个数,而min
和max
分别返回序列中最小和最大的元素。
>>> numbers = [100, 34, 678] >>> len(numbers) 3 >>> max(numbers) 678 >>> min(numbers) 34 >>> max(2, 3) 3 >>> min(9, 3, 2, 5) 2
基于前面的解释,这些代码应该很容易理解,但最后两个表达式可能例外。在这两个表达式中,调用max
和min
时指定的实参并不是序列,而直接将数作为实参。
4 . Python的主力:列表(list)
列表不同于元组和字符串的地方——列表是可变的,即可修改其内容。另外,列表有很多特有的方法。
函数(list):
鉴于不能像修改列表那样修改字符串,因此在有些情况下使用字符串来创建列表很有帮助。为此,可使用函数list(类)。
>>> list('Hello') ['H', 'e', 'l', 'l', 'o']
将字符列表(如前述代码中的字符列表)转换为字符串,可使用下面的表达式:
''.join(somelist)
''' ' '.join(somelist):将字符列表连接成字符串。 将字符列表、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串 ''' #:' '.join(somelist)将字符列表转换为字符串,前面' '里面设置连接符号 print(''.join(list_string)) #没有连接符 print('$'.join("China")) #连接符$
基本的列表操作:
可对列表执行所有的标准序列操作,如索引、切片、拼接和相乘,但列表的有趣之处在于它是可以修改的。修改列表的方式:给元素赋值、删除元素、给切片赋值以及使用列表的方法。(请注意,并非所有列表方法都会修改列表。)
修改列表:给元素赋值
>>> x = [1, 1, 1] >>> x[1] = 2 >>> x [1, 2, 1]
不能给不存在的元素赋值,因此如果列表的长度为2,就不能给索引为100的元素赋值。要这样做,列表的长度至少为101。可先对列表初始化(None)。
删除元素
从列表中删除元素也很容易,只需使用del
语句即可。
>>> names = ['Alice', 'Beth', 'Cecil', 'Dee-Dee', 'Earl'] >>> del names[2] >>> names ['Alice', 'Beth', 'Dee-Dee', 'Earl']
注意到Cecil彻底消失了,而列表的长度也从5变成了4。除用于删除列表元素外,del
语句还可用于删除其他东西。(比如字典内,还有可以删除变量)
>>> name = "zhang" >>> print(name) zhang >>> del name >>> print(name) #将会报错
给切片赋值
切片是一项极其强大的功能,而能够给切片赋值让这项功能显得更加强大。
>>> name = list('Perl') >>> name ['P', 'e', 'r', 'l'] >>> name[2:] = list('ar') >>> name ['P', 'e', 'a', 'r']
从上述代码可知,可同时给多个元素赋值。你可能认为,这有什么大不了的,分别给每个元素赋值不是一样的吗?确实如此,但通过使用切片赋值,可将切片替换为长度与其不同的序列。
>>> name = list('Perl') >>> name[1:] = list('ython') >>> name ['P', 'y', 't', 'h', 'o', 'n']
使用切片赋值还可在不替换原有元素的情况下插入新元素。
>>> numbers = [1, 5] >>> numbers[1:1] = [2, 3, 4] >>> numbers [1, 2, 3, 4, 5]
在这里,我“替换”了一个空切片,相当于插入了一个序列。你可采取相反的措施来删除切片。
>>> numbers [1, 2, 3, 4, 5] >>> numbers[1:4] = [] >>> numbers [1, 5]
与del numbers[1:4]
等效
列表方法:
方法是与对象(列表、数、字符串等)联系紧密的函数。通常,像下面这样调用方法:
object.method(arguments)
方法调用与函数调用很像,只是在方法名前加上了对象和句点。列表包含多个可用来查看或修改其内容的方法。
方法append
用于将一个对象附加到列表末尾
>>> lst = [1, 2, 3] >>> lst.append(4) >>> lst [1, 2, 3, 4]
不会返回修改后的新列表,而是直接修改旧列表
方法clear
就地清空列表的内容
>>> lst = [1, 2, 3] >>> lst.clear() >>> lst []
这类似于切片赋值语句lst[:] = []
。
方法copy
复制列表。前面说过,常规复制只是将另一个名称关联到列表
>>> a = [1, 2, 3] >>> b = a >>> b[1] = 4 >>> a [1, 4, 3]
要让a
和b
指向不同的列表,就必须将b
关联到a
的副本。
>>> a = [1, 2, 3] >>> b = a.copy() >>> b[1] = 4 >>> a [1, 2, 3]
这类似于使用a[:]
或list(a)
,它们也都复制a
。
方法count
计算指定的元素在列表中出现了多少次
>>> ['to', 'be', 'or', 'not', 'to', 'be'].count('to') 2 >>> x = [[1, 2], 1, 1, [2, 1, [1, 2]]] >>> x.count(1) 2 >>> x.count([1, 2]) 1
方法extend
让你能够同时将多个值附加到列表末尾,为此可将这些值组成的序列作为参数提供给方法extend
。换而言之,你可使用一个列表来扩展另一个列表。
>>> a = [1, 2, 3] >>> b = [4, 5, 6] >>> a.extend(b) >>> a [1, 2, 3, 4, 5, 6]
这可能看起来类似于拼接,但存在一个重要差别,那就是将修改被扩展的序列(这里是a
)。在常规拼接中,情况是返回一个全新的序列。
>>> a = [1, 2, 3] >>> b = [4, 5, 6] >>> a + b [1, 2, 3, 4, 5, 6] >>> a [1, 2, 3]
如你所见,拼接出来的列表与前一个示例扩展得到的列表完全相同,但在这里a
并没有被修改。鉴于常规拼接必须使用a
和b
的副本创建一个新列表,因此如果你要获得类似于下面的效果,拼接的效率将比extend
低:
>>> a = a + b
另外,拼接操作并非就地执行的,即它不会修改原来的列表。要获得与extend
相同的效果,可将列表赋给切片,如下所示:
>>> a = [1, 2, 3] >>> b = [4, 5, 6] >>> a[len(a):] = b >>> a [1, 2, 3, 4, 5, 6]
这虽然可行,但可读性不是很高。
方法index
在列表中查找指定值第一次出现的索引。
>>> knights = ['We', 'are', 'the', 'knights', 'who', 'say', 'ni'] >>> knights.index('who') 4 >>> knights.index('herring') Traceback (innermost last): File "<pyshell>", line 1, in ? knights.index('herring') ValueError: list.index(x): x not in list