一、列表
和字符串一样,列表也是序列类型,因此可以通过下标或者切片操作访问一个或者多个元素。但是,不一样的,列表是容器类型,是可以进行修改、更新的,即当我们进行修改列表元素,加入元素等操作的时候,是对原始对象自身的直接变更,而非新对象的创建。
列表可以以任何类型对象作为自己的元素(包括用户自定义类型),而且更为灵活的是,一个列表中可以同时容纳不同类型的对象(这是C/C++中的数组或vector所不能做到的)。
1.创建列表
1
2
3
4
|
listDemo1 = [ 123 , 'abc' , 45.6 , [ 'a' , 'b' , 'c' ], 7 - 9j ]
listDemo2 = [ None , 'something here' ] #first element is None
listDemo3 = [] #empty list
listDemo4 = list () #factory method. return an empty list
|
2.访问
1
2
|
listDemo1[ 0 ] #return 123
listDemo1[ 1 : 4 ] #return ['abc', 45.6, ['a', 'b', 'c']]
|
3.更新
1
2
3
4
5
6
|
listDemo1[ 0 ] + = 66
listDemo1.append( 'I am new comer' ) #追加一个新元素
listDemo1 + = [ 'append again' ] #再次追加一个元素
#注意:在这些过程中,listDemo1所指向的始终是原有的对象,没有新 #对象被创建,你可以多用id()测试一下 |
4.删除元素和自身
1
2
3
4
5
6
7
8
|
#删除一个元素 del listDemo1[ 0 ]
#删除多个元素 del listDemo[ 1 : 3 ]
#删除自身 del listDemo1
#使用pop()方法删除 a = listDemo2.pop[ 1 ] #删除下标为1的元素并赋予将其返回给a
|
5.操作符
标准类型操作符:=,<,>,==,<=,>=及cmp()函数
对列表使用比较操作符和cmp时的规则较为特殊,基本逻辑是这样的:两个列表的元素依次比较,直到有一方胜出。
序列类型操作
1
2
3
4
5
6
7
|
#对列表进行切片返回的仍然是列表 alpha = [ 'a' , 'b' , 'c' , [ 'd' , 'e' , 'f' ]]
alpha_part = alpha[ 2 :]
alpha_part #return ['c', ['d', 'e', 'f']]
#切片的基础上可以继续切片 alpha_aprt[ 1 :][: 2 ] #return ['d', 'e']
|
成员关系操作(in,not in)和重复操作"*“
用法固定,这里不再赘述
连接操作
前面的例子中演示过‘+’操作,此外可以使用extend()方法进行连接,以保证确实把新列表添加在了原有列表之中,而不是创建新的
1
2
3
4
|
origin = [ 1 , 2 , 4 ]
newList = [ 9 , 8 , 8 ]
origin.extend(newList) origin #return [1, 2, 4, 9, 8, 8]
|
6.内建函数
标准内建函数cmp()
前面刚刚说了,cmp()的比较方式和使用比较运算符(<,<=,>,>=,==,!=)是一样的,都是:两个列表的元素依次比较,直到有一方胜出。比较过程中,如果比较对象是不同类型,则要进行类型转换,你不应该完全依赖这些自动的类型转换,在进行比较之前,你应该保证对象的一致性,更重要的,这样的比较应该有意义。cmp()返回值为:1,0,-1
序列类型函数
len(), max(), min(), sorted(), reversed(), enumerate(), zip(), sum()——这些函数的用法前面已经讲过,这里不再重复,挑几个特殊的说一下:
1
2
3
4
5
6
7
8
9
|
#sorted()返回一个新创建的列表对对象 listDemo = [ 1 , 5 , 4 , 'A' ]
type ( sorted (listDemo)) #return <type 'list'>
#reversed()返回的是一个迭代器类型对象!! type ( reversed (listDemo)) #return <type 'listreverseiterator'>
#sum()作用于列表时,要求列表的元素都是数字类型 sum (listDemo) #return a error
|
迭代器的概念在后续的学习中会讲到,先明确它和列表对象有本质的区别!
list()函数是一个工厂函数,可以生产列表,同时可用于其它类型序列”转换“为列表,最后一个例子通过一个元组生产了一个列表:
1
2
3
4
5
|
list1 = list () #retur an empty list
list2 = list ([ 'a' , 'b' , 'c' ]) #produce a list
list3 = list ( 'abc' )
list3 #return ['a', 'b', 'c']
list4 = list (( 'a' , 'b' , 'c' )) # ret ['a', 'b', 'c']
|
7.列表类型的内建函数
以下介绍列表类型自己的方法,你可以通过dir(list)浏览所有的方法,继而通过help(list.method_name)或者help(list.method_name)或者list.method_name.__doc__的方式获取帮助信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#列表类型内建函数 ''' list.append(obj) 向列表中追加一个对象 list.count(obj) 返回对象obj在列表中出现的次数 list.extend(seq) 把序列seq的内容添加到列表中 list.insert(index,obj) 在列表索引为index的位置插入对象obj list.index(obj, i=0, j=len(list)) 返回列表中索引值在i和j之间的元素值为obj的所有索引
list.pop(index = -1) 删除列表中索引为index的元素并将其返回 list.remove(obj) 从列表中删除对象obj list.reverse() 原地翻转列表 list.sort(fun=None, key=None, reverse=False) 以指定的方式对列表排序,具体请help '''
|
需要指出的几点:
使用index内建方法时,如果找不到obj,会返回一个错误,这是你不乐意的,所以在返回其位置前,先用in或者not in成员关系操作符检查一下,因index方法默认认为要找的对象是一定存在的。
那些可以改变对象值的对象方法是没有返回值的,如sort(),reversed(),因它们作用在对象自身身上,不会返回新的对象。
extend()方法过去只能接受一个列表并将其追加到原列表中,现在可以支持任何可迭代对象,包括:元组,字符串,迭代器等
二、列表的典型应用:堆栈,队列
1.堆栈(Stack)
堆栈是一个后进先出(Last In First Out,LIFO)的数据结构,就像玩汉诺塔一样,最后放上去的盘子总是可以先拿下来,最先放上去的要最后拿下来;或者像我们穿衣服,最先穿上的,你总是最后才能脱下来:-)。在C++中,堆栈可以用vector容器构造出来,在Python中,使用Python构造堆栈更加容易和灵活:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#!/usr/bin/env python ''' stack_demo.py --- list based stack function ''' stack = [] #create an empty stack
def pushit(): #入栈函数
stack.append( raw_input ( 'Enter New String: ' ).strip())
def popit(): #出栈函数,strip可以去掉字符串两端的空白
if len (stack) = = 0 :
print 'Cannot pop from an empty stack!'
else :
print "Removed ['%s']" % stack.pop()
def viewstack(): #显示堆栈内容
print stack #calls str() internally
#define key to function commands CMDs = { 'u' :pushit, 'o' :popit, 'v' :viewstack}
def showmenu():
print '''
p(U)sh p(O)p (V)iew (Q)uit Enter choice: ''' ,
#main loop begin! while True :
while True :
try :
showmenu()
choice = raw_input ('')
except (EOFError, KeyboardInterrupt, IndexError):
choice = 'q'
print '\n You picked: [%s]' % choice
if choice not in 'uovq' :
print 'Invalid option, try again'
else :
break
if choice = = 'q' :
break
CMDs[choice]() #powerful usage of function and dict!
|
这段代码是有重大bug的,如果你输入'uo',则会出现异常,因上述代码是假定用户会听话的每次输入一个字符,你可以对其进行改进。内层循环用于获取“合理”的命令“键“,外层循环负责将”键“通过字典映射到函数,怎么样,很简单吧?
2.队列(Queue)
队列是一种先进先出(First In First Out,FIFO)结构,这比堆栈要容易理解多了,因为生活中处处都有队列,在ATM或银行柜台前排队,超市结账口,KFC点菜口等等,总之,先来先享受服务,后来的老老实实排队(当然,如果你有关系可以走后门的话那就另当别论了)。
将上面的堆栈代码修改成队列代码太简单了,先将所有的stack替换成queue,然后修改进队和出队函数,保证出去的是第一个进去的,新加入的排最后,此外再做一些微小的改动:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#!/usr/bin/env python ''' queue_demo.py --- list based queue function ''' queue = [] #create an empty queue
def EnQ(): #入队函数
queue.append( raw_input ( 'Enter New String: ' ).strip())
def DeQ(): #出队函数,strip可以去掉字符串两端的空白
if len (queue) = = 0 :
print 'Cannot pop from an empty queue!'
else :
print "Removed ['%s']" % queue.pop( 0 )
def viewqueue(): #显示队列内容
print queue #calls str() internally
#define key to function commands CMDs = { 'e' :EnQ, 'd' :DeQ, 'v' :viewqueue}
def showmenu():
print '''
(E)nQ (D)eQ (V)iew (Q)uit Enter choice: ''' ,
#main loop begin! while True :
while True :
try :
showmenu()
choice = raw_input ('').strip().lower()
except (EOFError, KeyboardInterrupt, IndexError):
choice = 'q'
print '\n You picked: [%s]' % choice
if choice[ 0 ] not in 'edvq' :
print 'Invalid option, try again'
else :
break
if choice[ 0 ] = = 'q' :
break
CMDs[choice[ 0 ]]() #powerful usage of function and dict!
|
这段代码解决了上个代码的Bug,首先在36行,对读入的命令用strip()去掉两端的空格,继而用lower()将其全部转化为小写,在41,46,48行,我们取choice[0]进行比较,即如果用户键入多个字符的话,我们认为第一个是有效的。但是,这样并不完美,我们不应该让用户关注大小写,也就是说,输入q和Q应该是等价的。你可以继续修改,直至作为“用户”的你可以满意。
三、元组
元组是一种和列表大不相同却又有太多相似之处的容器类型。不同之处很明显,元组用圆括号包裹,是一种不可更改的容器。因此它能用来做一些列表不能做的事,如用作一个字典的key。相同之处在于它们在操作和使用上很大程度是相似的,所以,这一节将着重描述元组和列表的不同之处。
1.创建
列表用“[]”者工厂函数list(),元组用“()"或工厂函数tuple()
2.访问
使用下标或者切片方式访问,和列表相同
3.更新(这是不可以的!)
1
2
3
4
|
tuple_demo = ( 1 , 2 , 4 )
tuple_demo[ 0 ] = 9 #retun an error!!
tuple_demo = ( 9 , 2 , 4 )
|
千万别认为在第四行你将对象更新了,这只是让tuple_demo指向了一个新的对象!不信的话用id()测试一下。总之,记住,元组类型不能更新。
特殊情况:如果元组的某个成员是列表,那么这个成员的成员是可以变更的:
1
2
|
a = ( 1 , 2 , 3 , 4 , [ 'a' , 'b' ])
a[ 4 ][ 1 ] = 'byte' # this is proved!
|
注意,这里并没有违反元组不可更新的原则,我们更改的是一个列表对象,可以这样认为:这个元组里面的第4号元素是到列表对象的引用,我们并没有更新这个引用!
4.删除
你不能删除一个元素,你只可以删除元组本身。 del tuple_name
5.操作符和内建函数
元组没有自己专用的操作符和内建函数,可能是缘于其是不可变量吧,内建方法也就被省了,这对我们来说并非坏事,减轻了我们学习的负担。
至于重复,连接,比较等操作,和列表一样,这里不再重复。
6.默认集合类型
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#所有多对象,逗号分隔的,没有明确用符号定义的集合都是元组类型 >>> 'abc' , 23 , 234.5
( 'abc' , 23 , 234.5 )
>>>x, y = 1 , 4
>>>x, y ( 1 , 4 )
#返回多对象的函数返回元组类型 def fool():
...
return obj1, obj2, obj3
var1, var2, var3 = fool()
|
7.单元素元组
1
2
|
single_tuple = ( 'xyz' ,) #别忘了这个逗号,否则不会得到你想要的
single_list = [ 'xyz' ] #对于列表就不存在这个问题
|
8.真的需要元组吗?
元组的存在关键在于其不可变,有时我们维护一组敏感数据,需要将它作为参数传递给不熟悉甚至不是自己写的API,为了保护数据不会被调用的函数篡改,这时候元组便派上用场了。tuple()和list()两个函数可以方便两种序列类型的转换,在参数传递的时候这便极为有用。
四、相关模块
1
2
3
4
5
6
7
8
9
10
11
|
#与序列类型相关的模块 print '''
array 受限制的序列类型,和数组一样,所以元素必须是同种类型 copy 提供浅拷贝和深拷贝能力 operator 包含函数调用形式的序列操作符 re Perl风格的正则表达式查找和匹配 StringIO 把长字符串作为文件来操作 cStringIO 把长字符串作为文件来操作,C版的,更快一些,不能被继承 textwrap 包装填充文本的函数 types 包含Python支持的所有类型 collections 高性能容器数据类型 ''' |
五、深拷贝和浅拷贝
Brown和Marry是一对夫妻,他们准备开两个银行账户,银行是这么做的:
1
2
3
|
husband = [ 'Brown' , [ 'savings' , 100 ]]
wife = husband
wife[ 0 ] = 'Marry'
|
两个账户应该是相同的,因此wife = husband,后再改一下名字应该没有什么问题,但问题出现了!
1
2
|
>>>wife, huaband ([ 'Marry' , 'savings' , 100 ], [ 'Marry' , 'savings' , 100 ])
|
名字成为了一样的!!(这时Brown先生表达了十分的不满)
深拷贝和浅拷贝(拷贝即copy)一定是针对容器类型而言的,对于非容器类型没有意义。在上例中,husband和wife实质上是指向同一对象的两个引用,因此更改一个就影响了“另一个”,其实是同一个。 这里拷贝给wife的只是引用,而不是对象,这样的拷贝称为浅拷贝。
银行马上做了改进:
1
2
3
4
5
6
7
8
9
10
|
person = [ 'name' , [ 'savings' , 0 ]]
husband = person[:] #slice copy
wife = list (person) #factory function copy
husband[ 0 ] = 'Brown' #change name
husband[ 1 ][ 1 ] = 100 #to save 100 dollar
wife[ 0 ] = 'Marry' #change name
wife[ 1 ][ 1 ] = 100 #to save 100 dollar
|
这下应该没问题了吧,使用了切片方法和工厂方法,应该是创建了两个不同的对象的,再也不会有冲突了!?
一天,Brown先生发了奖金,为了存点私房钱,他没有上交夫人,而是存了起来:
1
|
husband[ 1 ][ 1 ] + = 1000
|
奇怪的是,Marry夫人在ATM上查询自己的余额时,发现自己的账户多了1000 dollar!
1
2
|
>>>wife [ 'Marry' , [ 'savings' , '1100' ]]
|
和丈夫谈起这件怪事时,丈夫觉得有问题,于是和妻子到银行去咨询,结果可想而知,那1000 d居然是Brown先生的私房钱。(Marry很生气,但又很高新,因为“公共账户”对她来说挺好的,可以了解丈夫的财务情况,但Brown不满意,毕竟作为一个男人,没有些自己的“私房钱”总是不那么光彩)。
无论是切片方法还是工厂方法,这里做的都是浅拷贝,虽然wife和husband确实指向两个不同的对象,但这两个对象中的那个列表仍然是同一个列表对象,即两个对象中是同一个列表对象的引用,这就是上面问题的原因。
解决问题的方法是深度拷贝,使用copy模块的deepcopy方法:
1
2
3
4
5
6
7
8
9
|
import copy
person = [ 'name' , [ 'savings' , 0 ]]
wife = copy.deepcopy(person)
husband = copy.deepcopy(person)
wife[ 0 ] = 'Marry'
wife[ 1 ][ 1 ] + = 1000
... husband[ 1 ][ 1 ] + = 500
|
现在,wife和husband确实是两个不同的对象,而且其内部列表也确实指向了两个不同的列表,两个账户终于实现了私有化,这才是Brown先生想看到的!
问题最终解决了,Brown先生真诚的向夫人道了歉,Marry夫人也并非那么小心眼儿,生活回到了往日的平静......
六、小结
字符串、列表、元组以及我们下一节要学习的字典、集合是Python中最重要的几种数据类型,熟练掌握它们是使用Python进行程序设计的关键,多写一写,看一看,相信对你来说,一定会很简单,原因很简单:This is Python!
Python:列表,元组的更多相关文章
-
python列表元组
python列表元组 索引 切片 追加 删除 长度 循环 包含 定义一个列表 my_list = [] my_list = list() my_list = ['Michael', ' ...
-
Python—列表元组和字典
Python-列表元组和字典 列表 元组 字典 列表: 列表是Python中的一种数据结构,他可以存储不同类型的数据.尽量存储同一种类型 列表索引是从0开始的,我们可以通过索引来访问列表的值. 列表的 ...
-
【277】◀▶ Python 列表/元组/字典说明
目录: 前言 一.访问列表中的值 二.更新列表 三.删除列表元素 四.Python 列表脚本操作符 五.Python 列表函数 & 方法 参考:Python 列表(List)使用说明 列表截取 ...
-
Python 列表/元组/字典总结
序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推. Python有6个序列的内置类型,但最常见的是列表和元组. 序列 ...
-
python3笔记十八:python列表元组字典集合文件操作
一:学习内容 列表元组字典集合文件操作 二:列表元组字典集合文件操作 代码: import pickle #数据持久性模块 #封装的方法def OptionData(data,path): # ...
-
Python成长笔记 - 基础篇 (三)python列表元组、字典、集合
本节内容 列表.元组操作 字符串操作 字典操作 集合操作 文件操作 字符编码与转码 一.列表和元组的操作 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 定义 ...
-
Python列表,元组,字典,序列,引用
1.列表 # Filename: using_list.py # This is my shopping list shoplist=["apple", "mango&q ...
-
python 列表 元组 字典 集合
列表 lst = [i for i in range(10)] 切片 # 把下标小于2的显示出来 print(lst[:2]) # 把10个数有大到小输出 print(lst[::-1]) # 把下标 ...
-
Python 列表&;元组&;字典&;集合
列表(list) 有序性,可存储任意类型的值 通过偏移存取,支持索引来读取元素,第一个索引为0 ,倒数第一个索引为-1 可变性 ,支持切片.合并.删除等操作 可通过索引来向指定位置插入元素 可通过po ...
-
Python列表,元组,字典,集合详细操作
菜鸟学Python第五天 数据类型常用操作及内置方法 列表(list) ======================================基本使用====================== ...
随机推荐
-
[转][C/C++] 怎样不用中间变量temp 实现两个数交换
第一类方法也是常用的方法,通过多次的数值计算来完成交换,到现在知道的有下面三种: (1)加减法. a = a + b; b = a - b; a = a - b; 该方法可以交换整型和浮点型数值的变量 ...
-
转-sql中的case when的用法
Case具有两种格式.简单Case函数和Case搜索函数. --简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END ...
-
.NET常用方法——邮件发送
邮件发送类文件,可直接使用: 调用方法(实例化.静态调用): 实例化: string exception = ""; SendEmail.SendEmail SE = new Se ...
-
linux上配置subversion服务器端安装配置并使用svn,windows本地检出,设置同步更新服务器的钩子
参考http://my.oschina.net/junn/blog/164041 http://songxj.blog.51cto.com/620981/396113 http://5iwww.blo ...
-
Git 配置editor编辑器
Git 配置editor编辑器 在ubuntu系统下,Git默认的编辑器是命令行,学名叫V什么的,使用起来诸多不便 在编辑提交日志的时候,用的比较多. 可以选择unbuntu默认的文档编辑器作为git ...
-
Windows10远程报错:由于CredSSP加密Oracle修正
Windows10远程桌面连接 报错信息 : 网上找到方法 但是奈何是 "Win10家庭版" 不能使用这个办法,具体操作可以看最后的引用链接 !!!! 策略路径:"计算机 ...
-
mvc的cshtml Request取不到值
如果路径为:http://localhost:2317/food/1,这时用Request["id"]是取不到值的应该用: Request.RequestContext.Route ...
-
Java 设计模式系列(五)原型模式
Java 设计模式系列(五)原型模式 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象.这就是选型模式的用意. 一.原型模 ...
-
OpenCV学习笔记廿一:opencv_contrib模块
一,简介: 该库为新加入代码库的算法.
-
【模式识别】CART和GML AdaBoost MATLAB TOOLBOX
GML AdaBoost Matlab Toolbox是一款很优秀的AdaBoost工具箱,内部实现了Real AdaBoost, Gentle AdaBoost和Modest AdaBoost三种方 ...