课程内容和目标:
- 讲一些复合数据类型,它们可将较为简单数据对象汇总
- 介绍两个概念:元组和列表
- 讨论常见复合数据类型的基本操作
- 展示一个更为通用的对象合集——字典,以及创建和操作它们的方法
- 本课过后,编写的程序应该能够操作复合数据对象,或者处理标量对象,如数字和字符串
1.元组Tuples:
下面看一个例子:
>>>t1 = (1, 'two', 3)
>>>t1
(1, 'two', 3)
>>>t2 = (t1, 'four')
>>>t2
((1, 'two', 3), 'four')
接下来让t1和t2相加:
>>>t1 + t2
(1, 'two', 3, (1, 'two', 3), 'four')
我们可以索引元组里的元素:
>>>(t1+t2)[3]
(1, 'two', 3)
可以像字符串一样切片:
>>>(t1+t2)[2:5]
(3, (1, 'two', 3), 'four')
当元组中只有一个元素要定义,定义方法如下:
>>>t3 = ('five',)
>>>t1+t2+t3
(1, 'two', 3, (1, 'two',, 3), 'four', 'five')
为什么加个逗号呢?我们试一试以下代码:
>>>(3)
在Python中输出结果为:
3
仅仅是数字3,但我如果想要一个带有3的元组,就必须加个逗号予以区别
当有了元组后,就可以用来迭代,下面的例子是求两个数共有的公约数:
def findDivisors(n1, n2):
divisors = () #一个空的元组
for i in range(1, min(n1, n2)+1):
if n1%i==0 and n2%i==0:
divisors = divisors + (i,)
return divisors
同时,元组也可以在for循环里和range一样被遍历
2.列表:
与元组的区别:
①列表使用方括号而不是圆括号
②列表定义单个元素时不需要加逗号
③列表是可变的
下面我们看一段代码:
>>>Techs = ['MIT', 'Cal Tech']
>>>lvys = ['Harvard', 'Yale', 'Brown']
>>>Univs = [Techs, lvys]
>>>Univs1 = [['MIT', 'Cal Tech'], ['Harvard', 'Yale', 'Brown']]
>>>Univs
[['MIT', 'Cal Tech'], ['Harvard', 'Yale', 'Brown']]
>>>Univs1
[['MIT', 'Cal Tech'], ['Harvard', 'Yale', 'Brown']]
上面输出是一样的,但是还有有不同的地方。
append()方法可以改变列表,在列表后面添加指定的元素
>>>Techs.append('RPI')
>>>Techs
['MIT', 'Cal Tech', 'RPI']
>>>Univs
[['MIT', 'Cal Tech', 'RPI'], ['Harvard', 'Yale', 'Brown']]
>>>Univs1
[['MIT', 'Cal Tech'], ['Harvard', 'Yale', 'Brown']]
发现,Univs与Techs绑定了,即Univs的指针指向了Techs,所以当Techs改变时,Univs随之改变,而Univs1是单独定义的,没有指向Techs的指针,故不随着Techs改变而改变。
关于列表的迭代:
for e in Univs:
print('Univs contains')
print(e)
print(' which contains')
for u in e: #由于Univs中的元素本身就是列表,故可以再遍历
print(' '+u)
注意,用'+'串接方法和用append方法添加一个列表对列表来说是不同的,前者会让两个列表的元素处于同一水平,后者会让添加进的列表低一级
>>>flat = Techs + lvys
['MIT', 'Cal Tech','RIP', 'Harvard', 'Yale', 'Brown']
>>>Tech.append(lvys)
['MIT', 'Cal Tech','RIP', ['Harvard', 'Yale', 'Brown']]
下面在看一个例子,输出L1中和L2不同的元素:
def removeDups(L1, L2);
for e1 in L1:
if e1 in e2:
L1.remove(e1)
上述代码是有问题的,我们假如L1=[1,2,3,4],L2=[1,2,5,6],输出结果为L1=[2,3,4]
问题出在哪呢?在循环时,Python一直在用内部计数器追踪它所在的位置。随着L1的迭代,它会一直保留一个小索引,指示它的位置。当我决定从L1中移除某些元素时,我要进入其中并改变该列表,但我并没有调整计数器。因此,基本上讲,我可以改变列表的1个单位,这意味着计数器现在是指向了列表中的不同地方,因为如果我溢出了前面的一个元素并将该列表缩短了一个单位,举个例子,如果计数器指向了第二个元素,那么它现在实际上指向了列表中的第三个元素。解决方法如下:我们可以克隆一个列表
def removeDupsBetter(L1, L2):
L1Start = L1[:]
for e1 in L1Start:
for e1 in e2:
L1.remove(e1)
注意克隆列表是在列表后切片而不是直接L1Start = L1
3.一集对象:
概念:如果具有以下特征,那么就是一级对象——它有数据类型;它可以是数据结构的一个元素,比如列表;它可以出现在表达式中,比如赋值表达式,可以在赋值表达式的右手边;它也可以是函数的参数。函数也是一级对象,可以在函数中调用函数,下面看一个程序:
def applyToEach(L, f): #L是列表,f是函数
'''
想要该函数运行列表并在我们对元素调用函
数f时,依次替换元素
'''
for i in range(len(L)):
L[i] = f(L[i])
也可以将函数放到列表中:
def applyFuns(L, x): #L是个函数列表
for f in L:
print(f(x))
>>>applyFuns([abs, int, fact, fib], 4) #fact为阶乘,fib为斐波那契
4
4
24
5
4.对高阶函数进行一般化处理:
事实上,Python为我们提供了一些通用的高阶程序,其中一个为我们提供了过程映射。
map映射最简单的形式是联合函数——即有一个参数的函数,和一个包含合适参数的集合。因此函数成员最好是数字。基本上,map一般会按次序映射到列表的每一个元素,返回给我们对列表应用的结果。如:
>>>map(abs, [1,-2,3,-4])
[1,2,3,4]
5.字典:
字典是键值对的集合,键不再像元组和列表中的索引一样仅仅是整数,可以是任何形式。语法形式:
monthNumbers = {'Jan':1, 'Feb':2, 'Mar':3, 1:'Jan', 2:'Feb', 3:'Mar'}
>>>monthNumbers['Jan']
1
>>>monthNumbers[2]
'Feb'
注意字典里的词条是无序的,它们仅仅只能通过键来访问,而非索引
可对字典的操作:
①插入:
>>>monthNumbers['Apr'] = 4
>>>monthNumbers['Apr']
4
②迭代:
>>>collect = [] #创建一个新的列表
>>>for e in monthNumbers:
... collect.append(e)
>>>collect
[1, 2, 'Mar', 'Feb', 'Apr', 'Jan', 3]
将monthNumbers中的键放入了collect中
>>>monthNumbers.keys()
[1, 2, 'Mar', 'Feb', 'Apr', 'Jan', 3]
而keys()方法同样可以将键列出
键可以非常复杂,键可以为元组。但键不能为列表,因为键不可变