开始 python 从入门到精通 Lists and Tuples 列表与元祖

    技术2025-04-06  28

    List 列表

             序列在处理值的集合时非常有用。你可能有一个序列表示数据库中的一个人,第一个元素是他们的名字第二个元素是他们的年龄。如果写成列表(列表中的项目用逗号分隔,并用方括号括起来),则会看起来像这样:

    >>> edward = ['Edward Gumby', 42] 但是序列也可以包含其他序列,所以你可以列出这些人的列表

    >>> edward = ['Edward Gumby', 42] >>> john = ['John Smith', 50] >>> database = [edward, john] >>> database [['Edward Gumby', 42], ['John Smith', 50]]

     

    序列的操作

            对于所有序列类型,您都可以做某些事情。这些操作包括索(indexing)、切片(slicing)、添加(adding)、倍增(multiplying)和检查成员关系。此外,Python还有用于查找的内置函数序列的长度,以及寻找它的最大和最小元素。

    Indexing

    序列中的所有元素都是被编号的——从零开始向上。您可以使用a单独访问它们数,例如:

    >>> greeting = 'Hello' >>> greeting[0] 'H 这叫做索引。使用索引来获取元素。所有序列都可以用这种方式建立索引。当使用一个负索引时,Python从右边计数,也就是从最后一个元素计数。最后一个元素位于-1位置

    >>> 'Hello'[1] 'e

    Listing 2-1 包含一个示例程序,它询问您一年、一个月(数字从1到12)和一天(1到31),然后打印出日期和正确的月份名称,以此类推。

    # Print out a date, given year, month, and day as numbers months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] # A list with one ending for each number from 1 to 31 endings = ['st', 'nd', 'rd'] + 17 * ['th'] \ + ['st', 'nd', 'rd'] + 7 * ['th'] \ + ['st'] year = input('Year: ') month = input('Month (1-12): ') day = input('Day (1-31): ') month_number = int(month) day_number = int(day) # Remember to subtract 1 from month and day to get a correct index month_name = months[month_number-1] ordinal = day + endings[day_number-1] print(month_name + ' ' + ordinal + ', ' + year)

    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,元素11并不存在,但位于您想要的最后一个元素之后的第一步。明白了吗?如果你想从末尾开始计数,你可以使用负指标。

    >>> numbers[-3:-1] [8, 9] 但是,您似乎不能以这种方式访问最后一个元素。使用0作为元素“一步”怎么样

    >>> numbers[-3:0] [] 这并不是我们想要的结果。实际上,当片中最左的索引出现在序列的后面时与第二个相比(在本例中,倒数第三个比第一个晚),结果总是空的序列。幸运的是,您可以使用一个快捷方式:如果slice继续到序列的末尾,您可以简单地使用省略最后一个索引。

    >>> numbers[-3:] [8, 9, 10]  

    >>> numbers[:3] [1, 2, 3]

    事实上,如果你想复制整个序列,你可以把两个下标都去掉。

    >>> numbers[:] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] Longer Steps  

    切片时,可以(显式或隐式)指定切片的起始点和结束点。另一个参数,它通常是隐式的,就是步长。在规则切片中,步长为1,意味着slice从一个元素“移动”到下一个元素,返回开始和结束之间的所有元素。

    >>> 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] 您仍然可以使用前面提到的快捷方式。例如,如果你想要a的每四个元素

    >>> numbers[::4] [1, 5, 9] 当然,步长不可能是零——这不会有任何结果——但它可以是负的,也就是说从右到左提取元素。

    >>> 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做了“正确的事情”——对于正步长,它从开始到结束,对于一个负步长,它从结束到开始。

     

    Adding Sequences

    序列可以用加法(plus)操作符连接起来。

    Multiplication 一个序列乘以一个数字x会创建一个新的序列,其中原始序列重复x次:

    >>> 'python' * 5 'pythonpythonpythonpythonpython' >>> [42] * 10 [42, 42, 42, 42, 42, 42, 42, 42, 42, 42]  

    None, Empty Lists, and Initialization 空列表被简单地写成两个方括号([])—里面什么都没有。如果你想要房间的清单对于10个没有任何用处的元素,可以像以前一样使用[42]*10,或者可能更实际一些[0]* 10。现在,您有了一个包含10个0的列表。但是,有时候,你会想要一个值意思是“没有”,就像“我们这里还没有放任何东西。”这时你就不用None了。None是Python值确切的意思是“这里什么也没有。因此,如果您想初始化长度为10的列表,您可以执行以下操作:

    >>> sequence = [None] * 10 >>> sequence [None, None, None, None, None, None, None, None, None, None]  

    Listing 2-3包含一个程序,它(在屏幕上)打印一个由字符组成的“框”,该“框”居中在屏幕上显示,并与用户提供的句子大小相适应。代码可能看起来很复杂,但它基本上只是一种算术——计算出你需要多少空格、破折号等等,以便位置正确的事情

    # Prints a sentence in a centered "box" of correct width sentence = input("Sentence: ") screen_width = 80 text_width = len(sentence) box_width = text_width + 6 left_margin = (screen_width - box_width) // 2 print() print(' ' * left_margin + '+' + '-' * (box_width-2) + '+') print(' ' * left_margin + '| ' + ' ' * text_width + ' |') print(' ' * left_margin + '| ' + sentence + ' |') print(' ' * left_margin + '| ' + ' ' * text_width + ' |') print(' ' * left_margin + '+' + '-' * (box_width-2) + '+') print()

     

    Membership

    要检查序列中是否可以找到值,可以使用in操作符。这个操作符有点不同从目前为止讨论的(如乘法或加法)。它检查某件事是否真实返回相应的值:真对真,假对假。这样的运算符称为布尔运算符,真值叫做布尔值。有关布尔表达式的更多信息。 下面是一些使用in操作符的例子:

    >>> 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

    前两个示例使用成员资格测试来检查是否分别找到“w”和“x”在字符串权限。这可以是UNIX机器上检查编写和执行的脚本文件的权限。下一个示例检查是否在用户列表中找到提供的用户名(mlh)。如果您的程序强制执行某些安全策略,这可能非常有用。(在这种情况下,你可能会想要使用密码。)最后一个示例检查字符串主题是否包含字符串'$$$'。例如,它可以用作垃圾邮件过滤器的一部分。

     

    Length, Minimum, and Maximum

    内置函数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  

    Lists: Python’s Workhorse (列表:Python的主力)

    在前面的示例中,我使用了很多列表。您已经看到了它们是多么有用,但是本节讨论的是列表与元组和字符串的不同之处在于:列表是可更改的——也就是说,您可以更改它们它们有许多有用的专门方法。

    The list Function 因为字符串不能像列表那样被修改,所以有时候从a中创建一个列表是很有用的字符串。您可以使用list函数来完成此操作。

    >>> list('Hello') ['H', 'e', 'l', 'l', 'o'] 注意,列表适用于所有类型的序列,而不仅仅是字符串。

    基本的列表操作

     您可以对列表执行所有标准序列操作,比如索引、切片、连接、和繁殖。但是列表的有趣之处在于它们是可以修改的。在本节中,您将看到更改列表的一些方法:项分配、项删除、切片分配和列表方法(注意,并非所有的列表方法实际上都更改了它们的列表。)

     

    Changing Lists: Item Assignments

    更改列表很容易。你只需要像第一章中解释的那样使用普通的赋值。然而,而不是写一些像x = 2这样的东西,您可以使用索引符号来指定一个特定的、现有的位置,例如x[1] = 2. >>> x = [1, 1, 1] >>> x[1] = 2 >>> x [1, 2, 1]  

    Deleting Elements 从列表中删除元素也很容易。您可以使用del语句。

    >>> names = ['Alice', 'Beth', 'Cecil', 'Dee-Dee', 'Earl'] >>> del names[2] >>> names ['Alice', 'Beth', 'Dee-Dee', 'Earl'] 请注意塞西尔是如何完全消失的,列表的长度从5缩减到4。

    Assigning to Slices

    切片是一个非常强大的特性,而且可以为切片赋值这一事实使它更加强大。

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

     

    List Methods 方法是与某个对象紧密耦合的函数,该对象可以是列表、数字、字符串或其他对象。在通常,方法的调用是这样的:

    object.method(arguments) 方法调用看起来就像函数调用,只不过对象放在方法名前面,带有一个点分离他们。(你会在第7章中得到更详细的方法解释。)列表有几种方法允许您检查或修改它们的内容。

     

    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  

    extension方法允许您通过提供一个值序列来一次追加几个值想要追加。换句话说,原来的列表被另一个扩展了。

    >>> 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的副本其次,它没有使用extend那么有效如果你想要的是这样的东西: >>> a = a + b 而且,这不是一个就地操作—它不会修改原始操作。延长的效果可以通过分配给切片,如下:

    >>> 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

     

    insert方法用于将对象插入到列表中。

    >>> numbers = [1, 2, 3, 5, 6, 7] >>> numbers.insert(3, 'four') >>> numbers [1, 2, 3, 'four', 5, 6, 7] 与extend一样,您可以通过片分配实现insert。

    >>> numbers = [1, 2, 3, 5, 6, 7] >>> numbers[3:3] = ['four'] >>> numbers [1, 2, 3, 'four', 5, 6, 7] 这可能很花哨,但是很难像使用insert那样具有可读性。

     

    pop方法从列表中删除一个元素(默认情况下是最后一个)并返回它。

    >>> x = [1, 2, 3] >>> x.pop() 3 >>> x [1, 2] >>> x.pop(0) 1 >>> x [2]  

     

    remove方法用于删除第一次出现的值

    >>> x = ['to', 'be', 'or', 'not', 'to', 'be'] >>> x.remove('be') >>> x ['to', 'or', 'not', 'to', 'be'] >>> x.remove('bee') Traceback (innermost last): File "<pyshell>", line 1, in ? x.remove('bee') ValueError: list.remove(x): x not in list  

     

    reverse方法反转列表中的元素。(我想,这并不奇怪。)

    >>> x = [1, 2, 3] >>> x.reverse() >>> x [3, 2, 1]  

    sort方法用于就地对列表进行排序。排序“在适当的地方”意味着改变原来的列表元素是按顺序排序的,而不是简单地返回列表的排序副本。

    >>> x = [4, 6, 2, 1, 7, 9] >>> x.sort() >>> x [1, 2, 4, 6, 7, 9] 您已经遇到了一些修改列表而不返回任何内容的方法,并且在大多数情况下这种行为是非常自然的(例如append)。但我想强调一下这个案例中的行为因为很多人都被它搞糊涂了。这种混淆通常发生在用户需要对列表的副本进行排序,而保留原始副本。一种直观的(但错误的)方法如下:

    >>> x = [4, 6, 2, 1, 7, 9] >>> y = x.sort() # Don't do this! >>> print(y) None 因为sort修改x但不返回任何内容,所以最后得到的是一个已排序的x和一个不包含任何内容的y。一个 正确的做法是首先将y绑定到x的一个副本上,然后对y进行排序,如下所示:

    >>> x = [4, 6, 2, 1, 7, 9] >>> y = x.copy() >>> y.sort() >>> x [4, 6, 2, 1, 7, 9] >>> y [1, 2, 4, 6, 7, 9] 简单地将x赋值给y是行不通的,因为x和y都引用同一个列表。另一种方法获取一个列表的排序副本是使用排序函数。

    >>> x = [4, 6, 2, 1, 7, 9] >>> y = sorted(x) >>> x [4, 6, 2, 1, 7, 9] >>> y [1, 2, 4, 6, 7, 9] 这个函数实际上可以用于任何序列,但总是返回一个list

    >>> sorted('Python') ['P', 'h', 'n', 'o', 't', 'y']

     

    Advanced Sorting

    sort方法接受两个可选参数:key和reverse。如果你想使用他们,你通常指定他们的名字(所谓的关键字参数;关键参数类似于cmp参数:你提供一个函数,它在排序过程中使用。但是,该函数不是直接用于确定一个元素是否比另一个元素小,而是用于为每个元素创建一个键,并根据这些键对元素进行排序。例如,如果你想根据长度对元素进行排序,你可以使用len作为键函数

    >>> x = ['aardvark', 'abalone', 'acme', 'add', 'aerate'] >>> x.sort(key=len) >>> x ['add', 'acme', 'aerate', 'abalone', 'aardvark'] 另一个关键字参数,反向,只是一个真值(真或假;您将了解更多关于这些的信息表明是否应该反向排序的列表。

    >>> x = [4, 6, 2, 1, 7, 9] >>> x.sort(reverse=True) >>> x [9, 7, 6, 4, 2, 1]  

     

    元组:不变的序列(Tuples: Immutable Sequences)

    元组是序列,就像列表一样。唯一的区别是元组不能更改。(正如你所见注意,字符串也是如此。)元组语法很简单——如果用逗号分隔一些值,您自动拥有一个元组。

    >>> 1, 2, 3 (1, 2, 3) 如您所见,元组也可以(通常)括在括号中。

    >>> (1, 2, 3) (1, 2, 3) 空元组被写成两个不包含任何内容的括号。

    >>> () () 因此,您可能想知道如何编写包含单个值的元组。这有点奇怪——你必须把它包括进去 逗号,尽管只有一个值。

    >>> 42 42 >>> 42, (42,) >>> (42,) (42,) 最后两个示例生成长度为1的元组,而第一个根本不是元组。逗号是至关重要的。简单地添加括号没有用:(42)与42完全相同。然而,一个孤独的逗号可以完全更改表达式的值

    >>> 3 * (40 + 2) 126 >>> 3 * (40 + 2,) (42, 42, 42)

    tuple函数的工作方式与list非常相似:它接受一个序列参数和将其转换为元组。如果参数已经是元组,则不加更改地返回。

    >>> tuple([1, 2, 3]) (1, 2, 3) >>> tuple('abc') ('a', 'b', 'c') >>> tuple((1, 2, 3)) (1, 2, 3) 正如您可能已经收集到的那样,元组并不是非常复杂——并且实际上您可以使用它做的事情并不多 它们只是创建它们并访问它们的元素,这与其他序列的操作相同。

    >>> x = 1, 2, 3 >>> x[1] 2 >>> x[0:2] (1, 2) 元组的片也是元组,正如列表片本身也是列表一样。

    您需要了解元组有两个重要的原因。

    它们可以用作映射中的键(和集合的成员);列表不能用这个的方式。它们由一些内置函数和方法返回,这意味着你必须处理它们。只要你不试图改变它们,就“处理”它们通常意味着将它们视为列表(除非您需要诸如之类的方法)索引和计数,元组没有)。

    一般来说,列表可能足以满足您的排序需求。

     

    参考:Beginning Python From Novice to Professional, 3rd Edition 第二章

    Processed: 0.011, SQL: 9