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

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 第二章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值