Python 二 - 集合
list 和 tuple
list
list是Python内置的一种数据类型是列表,为一种有序的集合,可以随时添加和删除其中的元素。
例如,列出班级中所有同学的名字:
1 | classmates = ['Michael','Bob','Tracy'] |
可以用len()函数获取list元素的个数
1 | >>> len(classmates) |
用索引来访问list中每一个位置的元素,记得索引是从0开始的:
1 | classmates[0] |
当索引超出了范围时,Python会报一个IndexError错误,所以,要确保索引不要越界,记得最后一个元素的索引是len(classmates) - 1。
如果要取最后一个元素,除了计算索引位置外,还可以用-1做索引,直接获取最后一个元素:
1 | >>> classmates[-1] |
以此类推,可以获取倒数第2个、倒数第3个:
1 | classmates[-2] |
当然,倒数第4个就越界了。
list是一个可变的有序表,所以,可以往list中追加元素到末尾:
1 | classmates.append('Adam') |
也可以把元素插入到指定的位置,比如索引号为1的位置:
1 | classmates.insert(1, 'Jack') |
要删除list末尾的元素,用pop()方法:
1 | classmates.pop() |
要删除指定位置的元素,用pop(i)方法,其中i是索引位置:
1 | classmates.pop(1) |
要把某个元素替换成别的元素,可以直接赋值给对应的索引位置:
1 | classmates[1] = 'Sarah' |
list里面的元素的数据类型也可以不同,比如:
1 | L = ['Apple', 123, True] |
list元素也可以是另一个list,比如:
1 | s = ['python', 'java', ['asp', 'php'], 'scheme'] |
要注意s只有4个元素,其中s[2]又是一个list,如果拆开写就更容易理解了:
1 | p = ['asp', 'php'] |
要拿到’php’可以写p[1]或者s[2][1],因此s可以看成是一个二维数组,类似的还有三维、四维……数组,不过很少用到。
如果一个list中一个元素也没有,就是一个空的list,它的长度为0:
1 | L = [] |
tuple
另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改,比如同样是列出同学的名字:
1 | classmates = ('Michael', 'Bob', 'Tracy') |
现在,classmates这个tuple不能变了,它也没有append(),insert()这样的方法。其他获取元素的方法和list是一样的,你可以正常地使用classmates[0],classmates[-1],但不能赋值成另外的元素。
不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。
tuple的陷阱:当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来,比如:
1 | t = (1, 2) |
如果要定义一个空的tuple,可以写成():
1 | t = () |
但是,要定义一个只有1个元素的tuple,如果你这么定义:
1 | t = (1) |
定义的不是tuple,是1这个数!这是因为括号()既可以表示tuple,又可以表示数学公式中的小括号,这就产生了歧义,因此,Python规定,这种情况下,按小括号进行计算,计算结果自然是1。
所以,只有1个元素的tuple定义时必须加一个逗号,,来消除歧义:
1 | t = (1,) |
Python在显示只有1个元素的tuple时,也会加一个逗号,,以免你误解成数学计算意义上的括号。
最后来看一个“可变的”tuple:
1 | t = ('a', 'b', ['A', 'B']) |
这个tuple定义的时候有3个元素,分别是’a’,’b’和一个list。不是说tuple一旦定义后就不可变了吗?怎么后来又变了?
别急,我们先看看定义的时候tuple包含的3个元素:
当我们把list的元素’A’和’B’修改为’X’和’Y’后,tuple变为:
表面上看,tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向’a’,就不能改成指向’b’,指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!
小结
list和tuple是Python内置的有序集合,一个可变,一个不可变。根据需要来选择使用它们。
条件判断和循环
条件判断
根据Python的缩进规则,如果if语句判断是True,就把缩进的语句执行,否则不执行。
也可以给if添加一个else语句,如果if判断是False,就不执行if的内容,而执行else的内容
1 | if(3>2): |
注意不要少写冒号":"
1 | elif是else if的缩写,完全可以有多个elif,所以if语句的完整形式就是: |
循环
Python的循环有两种,一种是for…in循环,用于遍历list或者tuple
1 | colors = ['red','blue','green'] |
执行这段代码会依次打印colors的每一个元素
1 | red |
Python提供了一个range()函数,可以生成一个整数序列,我们可以计算一个1-100的整数之和
1 | sum = 0 |
第二种循环是while循环,和C语言一样,只要条件为True,就会执行循环体
1 | sum = 0 |
如果死循环了,记得用Ctrl + C退出循环
dict和set
dict
dict就是dictionary,在Java里也成为map,使用键值对(key-value)存储,具有极快的查找速度
例如记录同学们的成绩
1 | d = {'Michael':95,'Bob':75,'Tracy':85} |
除了初始化时指定外,存储value时,通过key放入(相同的key赋值的话,会覆盖掉之前的value):
1 | d['Adam'] = 76 |
如果key不存在dict会报错,为了避免这种错误,可以通过in判断key是否存在,或者使用dict的get方法,获取value,不存在的话会返回None
1 | dic = {"a":67,"c":12,"b":1} |
要删除一个key,使用pop(key)方法
与list相比,dict有以下几个特点
- 查找和插入的速度极快,不会随着key的增加而增加
- 需要占用大量内存,内存浪费多
而list相反 - 查找和插入的时间随着元素的增加而增加
- 占用空间小,浪费内存很小
Set
Set和dict类似,但是不存在value,只存一组key,而且key不能重复,所以Set中没有重复的key
1 | s = set([1,2,3,4,5,1,2,3,4,5]) |
重复的元素会被自动过滤掉
添加元素可以使用set的add(key)方法,可以重复添加,但不会有效果,删除元素使用remove(key)方法
1 | s = set([]) |
注意删除的元素必须存在,否则报错
set可以看成数学上的无序和无重复元素的集合,所以也可以做交集和并集的运算操作
1 | s1 = set([1,2,3,4]) |
函数
Python内置了很多很有用的函数,我们可以直接调用。可以在Python的官网上查看文档
可以在命令行通过help()查看某个函数的帮助信息
1 | help(abs) |
数据类型转换
Python内置常用的函数,比如int()函数就可以把其他数据类型转换为整数:
1 | int('123') |
函数名其实就是函数对象的引用,所以可以用一个变量指向该引用,实现别名的效果
1 | a = abs |
主要使用函数时,一定要传入正确的参数,否则会出错。
函数的定义
在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
1 | def fun(x,y): |
空函数
定义一个什么事也不做的空函数,可以使用pass语句
1 | def nop(): |
参数检查
Python会进行参数个数的检查,如果不对会抛出TypeError,但是类型并不会进行检查
默认参数
在定义时为某个参数初始化一个值,若调用时,该参数缺省时,便会使用默认的值
1 | def power(x,n = 2): |
可变参数
函数参数个数可变时,我们可以通过list或者tuple包装参数,传入函数,函数会接收到tuple
1 | def add(numbers): |
1 | def calc(*numbers): |
如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:
1 | >>> nums = [1, 2, 3] |
关键字参数
关键字参数允许传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装成为一个dict
1 | def person(name,age,**kw): |
函数person除了参数name和age外,还接受关键字参数kw。在调用该函数时,可以之传入必选参数,或者任意个关键字参数
1 | >>> person('Michael', 30) |
参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中的一部分,但定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。
比如:
1 | def fun(a,b,c=0,*args,**kw) |
调用时,Python接收器自动按照参数位置和参数名把对应的参数传进去
1 | >>> func(1, 2) |
最神奇的是通过一个tuple和dict,你也可以调用该函数:
1 | >>> args = (1, 2, 3, 4) |
递归函数
如果一个函数在内部调用自身,这个函数就是递归函数。
在Python中使用递归函数要注意栈溢出,在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
- 尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。

