[Python] 列表和元组的区别

【最近学习《Python核心编程》第二版,下面是提取出的一些重点。】

可以将列表和元组当成普通的“数组”,它能保存任意数量任意类型的Python 对象。和数组一样,通过从0 开始的数字索引访问元素,但是列表和元组可以存储不同类型的对象。

1.列表和元组有几处重要的区别:

a. 列表元素用中括号( [ ])包裹,元组元素用小括号(( ))包裹
b. 列表元素的个数及元素的值可以改变,元组不可以更改(尽管他们的内容可以)。
元组可以看成是只读的列表。通过切片运算( [ ] 和 [ : ] )可以得到子集,这一点与字符串的使用方法一样。

>>> aList = [1, 2, 3, 4]
>>> aList
[1, 2, 3, 4]
>>> aList[0]
1
>>> aList[2:]
[3, 4]
>>> aList[:3]
[1, 2, 3]
>>> aList[1] = 5
>>> aList
[1, 5, 3, 4]

元组也可以进行切片运算,得到的结果也是元组(不能被修改):

>>> aTuple = ('robots', 77, 93, 'try')
>>> aTuple
('robots', 77, 93, 'try')
>>> aTuple[:3]
('robots', 77, 93)
>>> aTuple[1] = 5
Traceback (innermost last):
File "<stdin>", line 1, in ?
TypeError: object doesn't support item assignment

核心笔记:列表 VS 元组

一个经常会被问到的问题是,"为什么我们要区分元组和列表变量?"这个问题也可以被表述为“我们真的需要两个相似的序列类型吗?”,一个原因是在有些情况下,使用其中的一种类型要优于使用另一种类型。
最好使用不可变类型变量的一个情况是,如果你在维护一些敏感的数据,并且需要把这些数据传递给一个并不了解的函数(或许是一个根本不是你写的API),作为一个只负责一个软件某一部分的工程师,如果你确信你的数据不会被调用的函数篡改,你会觉得安全了许多。
一个需要可变类型参数的例子是,如果你在管理动态数据集合时。你需要先把它们创建出来,逐渐地或者不定期的添加它们,或者有时还要移除一些单个的元素。这是一个必须使用可变类型对象的典型例子。幸运的是,通过内建的list()和tuple()转换函数,你可以非常轻松的在两者之间进行转换.
list()和tuple()函数允许你用一个列表来创建一个元组,反之亦然.如果你有一个元组变量,但你需要一个列表变量因为你要更新一下它的对象,这时list()函数就是你最好的帮手.如果你有一个列表变量,并且想把它传递给一个函数,或许一个API,而你又不想让任何人弄乱你的数据,这时tuple()函数就非常有用。

2. 列表的特殊特性

1) 用列表构建其他数据结构
列表有容器和可变的特性,这使得它非常灵活,用它来构建其他的数据结构不是件难事.我们马上能想到的是堆栈和队列.

堆栈
堆栈是一个后进先出(LIFO)的数据结构,其工作方式就像自助餐厅里面用于放盘子的弹簧支架.把盘子想像成对象,第一个离开堆栈的是你最后放上的那个.在栈上"push"元素是个常用术语,意思是把一个对象添加到堆栈中.反之,要删除一个元素,你可以把它"pop"出堆栈,

例6.3展示了一个菜单驱动的程序,它实现了一个简单的、用于存储字符串的堆栈.
逐行解释
1-3 行
一开始是Unix 的起始行,然后我们初始化堆栈(其实是个列表).
例6.3 用列表模拟堆栈(stack.py)
这个简单的脚本把列表做为堆栈用于存储和取回输入的字符串,这个菜单驱动驱动的程序
仅使用了列表的append()和pop()方法.

1 #!/usr/bin/env python
2
3 stack = []
4
5 def pushit():
6 stack.append(raw_input('Enter new string: ').strip())
7
8 def popit():
9 if len(stack) == 0:
10 print 'Cannot pop from an empty stack!'
11 else:
12 print 'Removed [', ‘stack.pop()‘, ']'
13
14 def viewstack():
15 print stack # calls str() internally
16
17 CMDs = {'u': pushit, 'o': popit, 'v': viewstack}
18
19 def showmenu():
20 pr = """
21 p(U)sh
22 p(O)p
23 (V)iew
24 (Q)uit
25
26 Enter choice: """
27
28 while True:
29 while True:
30 try:
31 choice = raw_input(pr).strip()[0].lower()
32 except (EOFError,KeyboardInterrupt,IndexError):
33 choice = 'q'
34
35 print '\nYou picked:[%s]' % choice
36 if choice not in 'uovq':
37 print 'Invalid option, try again'
38 else:
39 break
40
41 if choice == 'q':
42 break
43 CMDs[choice]()
44
45 if __name__ == '__main__':
46 showmenu()

5-6 行
pushit()函数添加一个元素(通过提示由用户输入)到堆栈中.

队列
队列是一种先进先出(FIFO)的数据类型,它的工作原理类似于超市中排队交钱或者银行里面的排队,队列里的第一个人首先接受服务(满心想第一个出去).新的元素通过"入队"的方式添加进队列的末尾,"出队"就是从队列的头部删除.下面的例子里面展示了这种操作,我们把上面的堆栈的例子进行了改造,用列表实现了一个简单的队列.

例6.4 把列表用做队列(queue.py)
这个例子中,我们把列表用做队列来存储和取回菜单驱动应用里面输入的字符串,只用到了列表的append()和pop()方法.

1 #!/usr/bin/env python
2
3 queue = []
4
5 def enQ():
6 queue.append(raw_input('Enter new string: ').strip())
7
8 def deQ():
9 if len(queue) == 0:
10 print 'Cannot pop from an empty queue!'
11 else:
12 print 'Removed [', ‘queue.pop(0)‘, ']'
13
14 def viewQ():
15 print queue # calls str() internally
16
17 CMDs = {'e': enQ, 'd': deQ, 'v': viewQ}
18
19 def showmenu():
20 pr = """
21 (E)nqueue
22 (D)equeue
23 (V)iew
24 (Q)uit
25
26 Enter choice: """
27
28 while True:
29 while True:
30 try:
31 choice = raw_input(pr).strip()[0].lower()
32 except (EOFError,KeyboardInterrupt,IndexError):
33 choice = 'q'
34
35 print '\nYou picked: [%s]' % choice
36 if choice not in 'devq':
37 print 'Invalid option, try again'
38 else:
39 break
40
41 if choice == 'q':
42 break
43 CMDs[choice]()
44
45 if __name__ == '__main__':
46 showmenu()

3. 元组的特殊特性.

1) 不可变性给元组带来了什么影响?
是的,我们在好多地方使用到了"不可变性"这个单词,除了这个词的计算机学科定义和实现,从应用的角度来考虑,这个词的底线是什么?一个数据类型成为不可变的到底意味着什么?

在三个标准不可变类型里面–数字,字符串和元组字符串–元组是受到影响最大的,一个数据类型是不可变的,简单来讲,就意味着一旦一个对象被定义了,它的值就不能再被更新,除非重新创建一个新的对象.对数字和字符串的影响不是很大,因为它们是标量类型,当它们代表的值改变时,这种结果是有意义的,是按照你所想要的方式进行访问的,而对于元组,事情就不是这样了。

因为元组是容器对象,很多时候你想改变的只是这个容器中的一个或者多个元素,不幸的是这是不可能的,切片操作符不能用作左值进行赋值。这和字符串没什么不同,切片操作只能用于只读的操作。

不可变并不是坏事,比如我们把数据传给一个不了解的API 时,可以确保我们的数据不会被修改。同样地,如果我们操作从一个函数返回的元组,可以通过内建list()函数把它转换成一个列表.

2) 元组也不是那么“不可变”
虽然元组是被定义成不可变的,但这并不影响它的灵活性。元组并不像我们想的那么不可变,这是什么意思?其实元组几个特定的行为让它看起来并不像我们先前声称的那么不可变.

比如说,既然我们可以把字符串组合在一起形成一个大字符串。那么把元组组合在一起形成一个大的元组也没什么不对,所以,连接操作可用,这个操作一点都没有改变那些小元组。
我们所作的是把它们的元素结合在一起.这里有几个例子:

>>> s = 'first'
>>> s = s + ' second'
>>> s
'first second'
>>>
>>> t = ('third', 'fourth')
>>> t
('third', 'fourth')
>>>
>>> t = t + ('fifth', 'sixth')
>>> t
('third', 'fourth', 'fifth', 'sixth')

同样的概念也适用于重复操作。重复操作只不过是多次复制同样的元素,再有,我们前面提到过可以用一个简单的函数调用把一个元组变成一个可变的列表。我们的最后一个特性可能会吓到你。你可以“修改”特定的元组元素,哇!这意味着什么?

虽然元组对象本身是不可变的,但这并不意味着元组包含的可变对象也不可变了。

>>> t = (['xyz', 123], 23, -103.4)
>>> t
(['xyz', 123], 23, -103.4)
>>> t[0][1]
123
>>> t[0][1] = ['abc', 'def']
>>> t
>(['xyz', ['abc', 'def']], 23, -103.4)

在上面的例子中,虽然t 是一个元组类型变量,但是我们设法通过替换它的第一个元素(一个列表对象)的项来“改变”了它。我们替换了t[0][1],原来是个整数,我们把它替换成了一个列表对象 [‘abc’,‘def’].虽然我们只是改变了一个可变对象,但在某种意义上讲,我们也“改变”了我们的元组类型变量。

3) 默认集合类型
所有的多对象的,逗号分隔的,没有明确用符号定义的,比如说像用方括号表示列表和用圆括号表示元组一样,等等这些集合默认的类型都是元组,下面是一个简单的示例:

>>> 'abc', -4.24e93, 18+6.6j, 'xyz'
('abc', -4.24e+093, (18+6.6j), 'xyz')
>>>
>>> x, y = 1, 2
>>> x, y
(1, 2)
发布了13 篇原创文章 · 获赞 2 · 访问量 2598

猜你喜欢

转载自blog.csdn.net/a10703060237/article/details/103575659