课程内容和目标:

  • 讲一些复合数据类型,它们可将较为简单数据对象汇总
  • 介绍两个概念:元组和列表
  • 讨论常见复合数据类型的基本操作
  • 展示一个更为通用的对象合集——字典,以及创建和操作它们的方法
  • 本课过后,编写的程序应该能够操作复合数据对象,或者处理标量对象,如数字和字符串

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()方法同样可以将键列出



键可以非常复杂,键可以为元组。但键不能为列表,因为键不可变