一、list
list:是Python内置的一种数据类型是列表,它是一种有序的集合,可以随时添加和删除其中的元素。list中的元素是按照顺序排列的,构造list非常简单,按照上面的代码,直接用 [ ] 把list的所有元素都括起来,就是一个list对象。通常,我们会把list赋值给一个变量,这样,就可以通过变量来引用list
L = ['adam', 95.5, 'lisa', 85, 'bart', 59]
print (L)
由于Python是动态语言,所以list中包含的元素并不要求都必须是同一种数据类型,我们完全可以在list中包含各种数据
L = ['Michael', 100, True]
因为list是一个有序集合,那么我们就可以通过下标的方式访问里边的元素(下标是从0开始的的)
L = ['adam', 95.5, 'lisa', 85, 'bart', 59]
print (L[0])
List下标可以是负数,-1表示最后一个元素,-2,-3一次表示倒数第二和倒数第三个元素
L = [95.5, 85, 59]
print (L[-1])
print (L[-2])
print (L[-3])
注意:当访问的下标越界时就会报错,比如L[-4],这时候会报错
如果想向list中添加元素,则可以使用append()函数(插入的位置为末尾)。要想插入到指定位置,则使用insert()方法
L = ['Adam', 'Lisa', 'Bart']
L.append('shulv')
L.insert(2,'Paul')//第一个参数是要插入的位置
print L
list中删除元素:删除一个元素,使用的是pop()方法,不传递参数时,删除的是最后一位,传递参数时为删除指定位置的元素,且返回值是 删除的那个元素的值
L = ['Adam', 'Lisa', 'Paul', 'Bart']
L.pop()
L.pop(0)
print L
list中替换元素:直接给对应下标重新赋值即可:L[0]=’abc’
二、tuple
tuple是另一种有序的列表,中文翻译为“ 元组 ”。tuple 和 list 非常类似,但是,tuple一旦创建完毕,就不能修改了。创建tuple和创建list唯一不同之处是用( )替代了[ ]。现在,这个 t 就不能改变了,tuple没有 append()方法,也没有insert()和pop()方法。不能再添加、删除和修改元素。访问元祖中的元素和list是一模一样的
需要注意的是,当tuple中包含一个元素的时候,我们需要这样写t=(1,)(是字符串的时候,也需要加“逗号”),也就是在后边加一个“逗号”。因为()既可以表示tuple,又可以作为括号表示运算时的优先级,结果 (1) 被Python解释器计算出结果 1,导致我们得到的不是tuple,而是整数 1。正是因为用()定义单元素的tuple有歧义,所以 Python 规定,单元素 tuple 要多加一个逗号“,”,这样就避免了歧义
下边我们看一个“可变”的tuple
t = (‘a’, ‘b’, [‘A’, ‘B’])
注意到 t 有 3 个元素:’a’,’b’和一个list:[‘A’, ‘B’]。list作为一个整体是tuple的第3个元素。list对象可以通过 t[2] 拿到:L=t[2]
然后,我们把list的两个元素改一改:
L[0] = ‘X’
L[1] = ‘Y’
再看看tuple的内容:
print t
(‘a’, ‘b’, [‘X’, ‘Y’])
不是说tuple一旦定义后就不可变了吗?怎么现在又变了?
别急,我们先看看定义的时候tuple包含的3个元素
当我们把list的元素’A’和’B’修改为’X’和’Y’后,tuple变为:
表面上看,tuple的元素确实变了,但其实变的不是 tuple 的元素,而是list的元素。
tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向’a’,就不能改成指向’b’,指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!
理解了“指向不变”后,要创建一个内容也不变的tuple怎么做?那就必须保证tuple的每一个元素本身也不能变。
三、dict
我们已经知道,list 和 tuple 可以用来表示顺序集合。dict是一种包含key,value的集合,它的表示方法为:
d = {
'Adam': 95,
'Lisa': 85,
'Bart': 59
}
花括号 {} 表示这是一个dict,然后按照 key: value, 写出来即可。最后一个 key: value 的逗号可以省略。由于dict也是集合,len() 函数可以计算任意集合的大小:len(d),输出为3
访问dict:
d = {
'Adam': 95,
'Lisa': 85,
'Bart': 59
}
可以简单地使用 d[key] 的形式来查找对应的 value,这和 list 很像,不同之处是,list 必须使用索引返回对应的元素,而dict使用key:print d[‘Adam’] 输出95
注意: 通过 key 访问 dict 的value,只要 key 存在,dict就返回对应的value。如果key不存在,会直接报错:KeyError。
要避免 KeyError 发生,有两个办法:
一是先判断一下 key 是否存在,用 in 操作符:
if 'Paul' in d:
print d['Paul']
如果 ‘Paul’ 不存在,if语句判断为False,自然不会执行 print d[‘Paul’] ,从而避免了错误。
二是使用dict本身提供的一个 get 方法,在Key不存在的时候,返回None:
print d.get('Bart')
59
print d.get('Paul')
None
dict特点:
dict的第一个特点是查找速度快,无论dict有10个元素还是10万个元素,查找速度都一样。而list的查找速度随着元素增加而逐渐下降。
不过dict的查找速度快不是没有代价的,dict的缺点是占用内存大,还会浪费很多内容,list正好相反,占用内存小,但是查找速度慢。
由于dict是按 key 查找,所以,在一个dict中,key不能重复。
dict的第二个特点就是存储的key-value序对是没有顺序的!这和list不一样:
d = {
'Adam': 95,
'Lisa': 85,
'Bart': 59
}
当我们试图打印这个dict时打印的顺序不一定是我们创建时的顺序,而且,不同的机器打印的顺序都可能不同,这说明dict内部是无序的,不能用dict存储有序的集合。
dict的第三个特点是作为 key 的元素必须不可变,Python的基本类型如字符串、整数、浮点数都是不可变的,都可以作为 key。但是list是可变的,就不能作为 key。
更新dict:
dict是可变的,也就是说,我们可以随时往dict中添加新的 key-value。比如已有dict:
d = {
'Adam': 95,
'Lisa': 85,
'Bart': 59
}
d['Paul'] = 72
print(L)
{'Lisa': 85, 'Paul': 72, 'Adam': 95, 'Bart': 59}
如果 key 已经存在,则赋值会用新的 value 替换掉原来的 value
遍历dict:
d = {
'Adam': 95,
'Lisa': 85,
'Bart': 59
}
for key in d:
print key + ':',d[key]
四、set
dict的作用是建立一组 key 和一组 value 的映射关系,dict的key是不能重复的。
有的时候,我们只想要 dict 的 key,不关心 key 对应的 value,目的就是保证这个集合的元素不会重复,这时,set就派上用场了。
set 持有一系列元素,这一点和 list 很像,但是set的元素没有重复,而且是无序的,这点和 dict 的 key很像。
创建 set 的方式是调用 set() 并传入一个 list,list的元素将作为set的元素:
s = set(['A', 'B', 'C'])
可以查看 set 的内容:
print s
set([‘A’, ‘C’, ‘B’])
请注意,上述打印的形式类似 list, 但它不是 list,仔细看还可以发现,打印的顺序和原始 list 的顺序有可能是不同的,因为set内部存储的元素是无序的。
因为set不能包含重复的元素,所以,当我们传入包含重复元素的 list 会怎么样呢?
s = set(['A', 'B', 'C', 'C'])
print s
set(['A', 'C', 'B'])
len(s)
3
结果显示,set会自动去掉重复的元素,原来的list有4个元素,但set只有3个元素。
访问set:
由于set存储的是无序集合,所以我们没法通过索引来访问。访问 set中的某个元素实际上就是判断一个元素是否在set中。
例如,存储了班里同学名字的set:
s = set(['Adam', 'Lisa', 'Bart', 'Paul'])
我们可以用 in 操作符判断:(在就返回true,不在返回false)
Bart是该班的同学吗?
‘Bart’ in s
True
set的特点:
set的内部结构和dict很像,唯一区别是不存储value,因此,判断一个元素是否在set中速度很快。set存储的元素和dict的key类似,必须是不变对象,因此,任何可变对象是不能放入set中的。最后,set存储的元素也是没有顺序的。set的这些特点,可以应用在哪些地方呢?
星期一到星期日可以用字符串’MON’, ‘TUE’, … ‘SUN’表示。
假设我们让用户输入星期一至星期日的某天,如何判断用户的输入是否是一个有效的星期呢?
可以用 if 语句判断,但这样做非常繁琐
如果事先创建好一个set,包含’MON’ ~ ‘SUN’:
weekdays = set([‘MON’, ‘TUE’, ‘WED’, ‘THU’, ‘FRI’, ‘SAT’, ‘SUN’])
再判断输入是否有效,只需要判断该字符串是否在set中:
x = '???' # 用户输入的字符串
if x in weekdays:
print 'input ok'
else:
print 'input error'
这样一来,代码就简单多了。
遍历set:
由于 set 也是一个集合,所以,遍历 set 和遍历 list 类似,都可以通过 for 循环实现。
直接使用 for 循环可以遍历 set 的元素:
s = set(['Adam', 'Lisa', 'Bart'])
for name in s:
... print name
...
Lisa
Adam
Bart
注意: 观察 for 循环在遍历set时,元素的顺序和list的顺序很可能是不同的,而且不同的机器上运行的结果也可能不同。
更新set:
由于set存储的是一组不重复的无序元素,因此,更新set主要做两件事:一是把新的元素添加到set中,二是把已有元素从set中删除。添加元素时,用set的add()方法:
s = set([1, 2, 3])
s.add(4)
print s
set([1, 2, 3, 4])
如果添加的元素已经存在于set中,add()不会报错,但是不会加进去了:
s = set([1, 2, 3])
s.add(3)
print s
set([1, 2, 3])
删除set中的元素时,用set的remove()方法:
s = set([1, 2, 3, 4])
s.remove(4)
print s
set([1, 2, 3])
如果删除的元素不存在set中,remove()会报错:
s = set([1, 2, 3])
s.remove(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 4
所以用add()可以直接添加,而remove()前需要判断。
五、切片
(1)对list进行切片
取一个list的部分元素是非常常见的操作。比如,一个list如下:
L = ['Adam', 'Lisa', 'Bart', 'Paul']
取前3个元素,应该怎么做?
笨办法:
[L[0], L[1], L[2]]
['Adam', 'Lisa', 'Bart']
之所以是笨办法是因为扩展一下,取前N个元素就没辙了。取前N个元素,也就是索引为0-(N-1)的元素,可以用循环:
r = []
n = 3
for i in range(n):
... r.append(L[i])
...
print r
['Adam', 'Lisa', 'Bart']
对这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符,能大大简化这种操作。
对应上面的问题,取前3个元素,用一行代码就可以完成切片:
L[0:3]
[‘Adam’, ‘Lisa’, ‘Bart’]
L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。
如果第一个索引是0,还可以省略:
L[:3]
[‘Adam’, ‘Lisa’, ‘Bart’]
也可以从索引1开始,取出2个元素出来:
L[1:3]
[‘Lisa’, ‘Bart’]
只用一个 : ,表示从头到尾:
L[:]
[‘Adam’, ‘Lisa’, ‘Bart’, ‘Paul’]
因此,L[:]实际上复制出了一个新list。
切片操作还可以指定第三个参数:
L[::2]
[‘Adam’, ‘Bart’]
第三个参数表示每N个取一个,上面的 L[::2] 会每两个元素取出一个来,也就是隔一个取一个。
把list换成tuple,切片操作完全相同,只是切片的结果也变成了tuple。
(2)倒序切片
对于list,既然Python支持L[-1]取倒数第一个元素,那么它同样支持倒数切片,试试:
L = ['Adam', 'Lisa', 'Bart', 'Paul']
L[-2:]
输出:['Bart', 'Paul']
L[:-2]
输出:['Adam', 'Lisa']
L[-3:-1]
输出:['Lisa', 'Bart']
L[-4:-1:2]
输出:['Adam', 'Bart']
记住倒数第一个元素的索引是-1。倒序切片包含起始索引,不包含结束索引。
(3)对字符串切片
字符串 ‘xxx’和 Unicode字符串 u’xxx’也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串:
'ABCDEFG'[:3]
输出:'ABC'
'ABCDEFG'[-3:]
输出:'EFG'
'ABCDEFG'[::2]
输出:'ACEG'
在很多编程语言中,针对字符串提供了很多各种截取函数,其实目的就是对字符串切片。Python没有针对字符串的截取函数,只需要切片一个操作就可以完成,非常简单。
六、迭代
(1)什么是迭代
在Python中,如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们成为迭代(Iteration)。
在Python中,迭代是通过 for … in 来完成的,而很多语言比如C或者Java,迭代list是通过下标完成的,比如Java代码:
for (i=0; i<list.length; i++) {
n = list[i];
}
可以看出,Python的for循环抽象程度要高于Java的for循环。
因为 Python 的 for循环不仅可以用在list或tuple上,还可以作用在其他任何可迭代对象上。
因此,迭代操作就是对于一个集合,无论该集合是有序还是无序,我们用 for 循环总是可以依次取出集合的每一个元素。
注意: 集合是指包含一组元素的数据结构,我们已经介绍的包括:
**1. 有序集合:**list,tuple,str和unicode;
**2. 无序集合:**set
**3. 无序集合并且具有 key-value 对:**dict
而迭代是一个动词,它指的是一种操作,在Python中,就是 for 循环。
迭代与按下标访问数组最大的不同是,后者是一种具体的迭代实现方式,而前者只关心迭代结果,根本不关心迭代内部是如何实现的。
(2)索引迭代
Python中,迭代永远是取出元素本身,而非元素的索引。
对于有序集合,元素确实是有索引的。有的时候,我们确实想在 for 循环中拿到索引,怎么办?
方法是使用 enumerate() 函数:
L = ['Adam', 'Lisa', 'Bart', 'Paul']
for index, name in enumerate(L):
... print index, '-', name
输出:
0 - Adam
1 - Lisa
2 - Bart
3 - Paul
使用 enumerate() 函数,我们可以在for循环中同时绑定索引index和元素name。但是,这不是 enumerate() 的特殊语法。实际上,enumerate() 函数把:
[‘Adam’, ‘Lisa’, ‘Bart’, ‘Paul’]
变成了类似:
[(0, ‘Adam’), (1, ‘Lisa’), (2, ‘Bart’), (3, ‘Paul’)]
因此,迭代的每一个元素实际上是一个tuple:
for t in enumerate(L):
index = t[0]
name = t[1]
print index, '-', name
如果我们知道每个tuple元素都包含两个元素,for循环又可以进一步简写为:
for index, name in enumerate(L):
print index, ‘-‘, name
这样不但代码更简单,而且还少了两条赋值语句。
可见,索引迭代也不是真的按索引访问,而是由 enumerate() 函数自动把每个元素变成 (index, element) 这样的tuple,再迭代,就同时获得了索引和元素本身。
(3)迭代dict的value
我们已经了解了dict对象本身就是可迭代对象,用 for 循环直接迭代 dict,可以每次拿到dict的一个key。
如果我们希望迭代 dict 对象的value,应该怎么做?
dict 对象有一个 values() 方法,这个方法把dict转换成一个包含所有value的list,这样,我们迭代的就是 dict的每一个 value:
d = { 'Adam': 95, 'Lisa': 85, 'Bart': 59 }
print d.values()
[85,59,95]
for v in d.values():
print v
85
59
95
如果仔细阅读Python的文档,还可以发现,dict除了values()方法外,还有一个 itervalues() 方法,用 itervalues() 方法替代 values() 方法,迭代效果完全一样:
d = { 'Adam': 95, 'Lisa': 85, 'Bart': 59 }
print d.itervalues()
<dictionary-valueiterator object at 0x106adbb50>
for v in d.itervalues():
print v
85
95
59
那这两个方法有何不同之处呢?
1. values() 方法实际上把一个 dict 转换成了包含 value 的list。
2. 但是 itervalues() 方法不会转换,它会在迭代过程中依次从 dict 中取出 value,所以 itervalues() 方法比 values() 方法节省了生成 list 所需的内存。
- 打印 itervalues() 发现它返回一个 对象,这说明在Python中,for 循环可作用的迭代对象远不止 list,tuple,str,unicode,dict等,任何可迭代对象都可以作用于for循环,而内部如何迭代我们通常并不用关心。
如果一个对象说自己可迭代,那我们就直接用 for 循环去迭代它,可见,迭代是一种抽象的数据操作,它不对迭代对象内部的数据有任何要求。
(4)迭代dict的key和value
我们了解了如何迭代 dict 的key和value,那么,在一个 for 循环中,能否同时迭代 key和value?答案是肯定的。
首先,我们看看 dict 对象的 items() 方法返回的值:
d = { 'Adam': 95, 'Lisa': 85, 'Bart': 59 }
print d.items()
输出:[('Lisa', 85), ('Adam', 95), ('Bart', 59)]
可以看到,items() 方法把dict对象转换成了包含tuple的list,我们对这个list进行迭代,可以同时获得key和value:
for key, value in d.items():
... print key, ':', value
输出:
Lisa : 85
Adam : 95
Bart : 59
和 values() 有一个 itervalues() 类似, items() 也有一个对应的 iteritems(),iteritems() 不把dict转换成list,而是在迭代过程中不断给出 tuple,所以, iteritems() 不占用额外的内存。
七、列表生成式
(1)生成列表
要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],我们可以用range(1, 11):
range(1, 11)
输出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
但如果要生成[1x1, 2x2, 3x3, …, 10x10]怎么做?方法一是循环:
L = []
for x in range(1, 11):
... L.append(x * x)
...
>>> L
输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的list:
[x * x for x in range(1, 11)]
输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
这种写法就是Python特有的列表生成式。利用列表生成式,可以以非常简洁的代码生成 list。
写列表生成式时,把要生成的元素 x * x 放到前面,后面跟 for 循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。
(2)条件过滤
列表生成式的 for 循环后面还可以加上 if 判断。例如:
[x * x for x in range(1, 11)]
输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
如果我们只想要偶数的平方,不改动 range()的情况下,可以加上 if 来筛选:
[x * x for x in range(1, 11) if x % 2 == 0]
输出:[4, 16, 36, 64, 100]
有了 if 条件,只有 if 判断为 True 的时候,才把循环的当前元素添加到列表中。
(3)多层表达式
for循环可以嵌套,因此,在列表生成式中,也可以用多层 for 循环来生成列表。
对于字符串 ‘ABC’ 和 ‘123’,可以使用两层循环,生成全排列:
[m + n for m in 'ABC' for n in '123']
输出:['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']
翻译成循环代码就像下面这样:
L = []
for m in 'ABC':
for n in '123':
L.append(m + n)
初学python,希望这些能够对大家有所帮助^_^,共同进步!