Python容器
列表(list)、元组(tuple)、集合(set)和字典(dict)是容器类型的,顾名思义,它们就像容器一样,可以装进各种不同类型的数据,这些容器数据类型还能互相搭配使用,是学习Python的关键内容。
容器数据类型的比较
Python的容器数据类型分为元组(tuple)、列表(list)、字典(dict)与集合(set),它们各有各的使用方法与限制。对象可分为可变(mutable)对象与不可变(immutable)对象两类,不可变对象一旦创建就不能改变其内容,其中只有元组是不可变对象,其他三种都是可变对象。 下面先对4种容器数据类型做简单的介绍。
- 元组(tuple):数据放置于括号“()”内,数据有顺序性,是不可变对象。
- 列表(list):数据放置于中括号“[]”内,数据有顺序性,是可变对象。
- 字典(dict):是dictionary的缩写,数据放置于大括号“{}”内,是“键(key)”与“值(value)”对应的对象,是可变对象。
- 集合(set):类似数学中集合的概念,数据放置于大括号“{}”内,是可变对象,数据具有无序与互异的特性。
列表(list)
使用单个变量存储数据时,当程序变量需求不多时,这种做法不会有太大问题。为了方便存储多个相关的数据,大部分程序设计语言会以数组方式来处理,与其他的程序设计语言都有的“数组”数据结构不同。
在Python语言中是以列表来扮演存储大量有序数据的角色,它是一串由逗号分隔的值,并用中括号“[]”括起来,如下所示:
fruitlist = ["Apple", "Orange", "Lemon", "Mango"]
上面的列表对象共有4个元素,长度是4,利用中括号“[]”配合元素的下标(index)就能存取每一个元素,下标从0开始,从左到右分别是fruitlist[0]
、fruitlist[1]
,以此类推。
列表(list)是元素的有序集合,列表的元素可以是Python语言支持的任意类型。初学者一般习惯用一对方括号([ ])来创建列表,标准的写法是用list( )来实例化list类。
列表的方法有很多,可以实现列表末尾追加元素、指定位置插入元素、删除指定元素或指定索引位置的元素、返回元素索引、排序等操作。此外,列表的索引、切片也非常灵活,很多操作都能给人惊喜。
现将同学cathy的个人信息统一放到列表中,代码如下:
cathy = ["cathy",10,138.5,True,None] # cathy的个人信息
score = [90,100,98,95] # 各科成绩
name = list("cathy") # 利用list()函数初始化一个列表
print(name) # 输出结果:['c', 'a', 't', 'h', 'y']
a = list() # 创建一个空列表,可以传入列表、元组、字符串等迭代对象
- 列表内的元素用方括号([ ])包裹。
- 列表内不同元素之间使用逗号(,)分隔。
- 列表内可以包含任何数据类型,也可以包含另一个列表。
- 可以使用list()函数生成一个列表。
创建列表
列表可以是空列表,列表中的元素可以包含不同的数据类型或其他的子列表。下面都是正确的列表表示方式:
data = [] #空的列表
data1 = [28, 16, 55] #存储数值的列表对象
data2 = ['1966', 50, 'Judy'] #含有不同类型的列表
data3 = ['Math', [88, 92], 'English', [65, 91]]
Python语言提供了生成式(Comprehension)的做法,是一种创建列表更快速,更有弹性的做法,列表中括号里面可以结合for语句以及其他if或for语句的表达式,而表达式所产生的结果就是列表的元素,例如:
>>> list1 =[i for i in range(1,6)]
>>> list1
[1, 2, 3, 4, 5]
列表的常用内建函数
可以使用列表自带的方法实现列表的访问、增加、删除和倒序等操作。仔细阅读以下代码及注释。
cathy = ["cathy",10,138.5,True,None] # cathy的个人信息
a = cathy[0] # 下标法获取第1个元素(姓名):cathy
b = cathy[1:3] # 使用切片获取下标1到下标3之前的子序列:[10, 138.5]
c = cathy[1:-2] # 切片下标也可以倒着数,-1对应最后一个元素:[10, 138.5]
d = cathy[:3] # 获取从开始到下标3之前的子序列:['cathy', 10, 138.5]
e = cathy[2:] # 获取下标2开始到结尾的子序列:[138.5, True, None]
cathy[2] = 140.2 # 将第3个元素修改为140.2
10 in cathy # 判断10是否在列表中,True
cathy.append(28) # 将体重添加到列表末尾
print(cathy) # ['cathy', 10, 140.2, True, None, 28]
cathy.insert(2,"中国") # 将国籍插入到第2个元素之后
print(cathy) # ['cathy', 10, '中国', 140.2, True, None, 28]
cathy.pop() # 默认删除最后一个元素
print(cathy) # ['cathy', 10, '中国', 140.2, True, None]
cathy.remove(10) # 删除第1个符合条件的元素
print(cathy) # ['cathy', '中国', 140.2, True, None]
cathy.reverse() # 倒序
print(cathy) # [None, True, 140.2, '中国', 'cathy']
cathy.extend([4,5,7,4,9]) # 列表后接列表[4,5,7,4,9]
len(L)
返回列表对象L的长度,即该列表包含几个元素,例如:
fruitlist = ["Apple", "Orange", "Lemon"]
print( len(fruitlist) ) #长度=3
sum()
内建函数sum()用于计算总分。
max(L)
返回列表对象L中最大的元素,例如:
print(max([1,3,5,7,9])) #9
min(L)
返回列表对象L中最小的元素,例如:
print(min([1,3,5,7,9])) #1
附加元素append()
append()方法用于将新的元素加到列表末端,例如:
fruitlist = ["Apple", "Orange", "Lemon"]
fruitlist.append("Mango")
上面程序语句的执行结果为:['Apple','Orange','Lemon','Mango']
现在要使用列表存储另一个同学terry的信息,已知除了姓名以外,其他的信息跟cathy一样。通过以下操作就可以得到同学terry的列表。
#cathy的个人信息
cathy_list = ["cathy",10,138.5,True,None]
terry_list = cathy_list # 将cathy_list赋给变量terry_list
terry_list[0] = "terry" # 修改terry的姓名
print(terry_list) # 打印terry信息:['terry', 10, 138.5, True, None]
print(cathy_list) # 打印cathy信息:['terry', 10, 138.5, True, None]
和大家的预期不同的是,cathy_list中的姓名也变成terry了,但是我们并未修改cathy_list的姓名,这是什么原因呢?
原来在执行terry_list=cathy_list时,程序并不会将cathy_list的值复制一遍,然后赋给terry_list,而是简单地为cathy_list的值即["cathy",10,138.5,True,None]
建立了一个引用,相当于cathy_list和terry_list都是指向同一个值的指针,所以当terry_list中的值改变后,cathy_list的值也会跟着变。可以通过id()函数来获取变量的地址。
实现代码如下:
print(id(cathy_list)) #获取cathy_list的地址:2011809417032
print(id(terry_list)) #获取terry_list的地址:2011809417032
结果显示,cathy_list和terry_list这两个变量均指向同一个地址。如何解决这个问题呢?可以使用copy()函数将值复制一份,再赋给terry_list,实现代码如下:
#terry_list = cathy_list #删除该条语句
terry_list = cathy_list.copy() #将值复制一份赋给变量terry_list
字典(dict)
dict(字典)是dictionary的缩写,字典的本质是无序的键值对,数据放置于大括号“{}”内,每一项数据是一对key-value,格式如下:
{key:value}
将同学cathy各科的成绩保存于列表score中,实现代码如下:
score = [90,100,98,95] #成绩
如果想要获取cathy的语文成绩,如何做到呢?除非事先将每门课的位置都做了记录,否则无论如何是获取不到语文成绩的。当需要对数据做明确的标注,以供别人理解和处理时,使用列表就不太方便了,这时字典就派上用场了。
字典是一种非常常见的“键-值”(key-value)映射结构,它为每一个元素分配了一个唯一的key,你无须关心位置,通过key就可以获取对应的值。下面来看一下使用字典保存的成绩:
score1 = {"math":90,"chinese":100,"english":98,"PE":95} #成绩字典
print(score1["chinese"])
- 字典内的元素用大括号({})包裹。
- 使用key:value的形式存储一个元素,如”math”:90,字符串math是分数90的key。
- 字典内不同键值对之间采用逗号(,)分隔。
- 字典是无序的,字典中的元素是通过key来访问的,如
score1["chinese"]
得到语文成绩。
创建字典
dict中的key必须是不可变的(immutable)数据类型,例如数字、字符串,而value则没有限制,可以是数字、字符串、列表、元组等,数据之间必须以逗号“,”隔开,例如:
d={'name':'Andy', 'age':18, 'city':'上海'}
也可以使用dict()函数初始化字典,实现代码如下:
score2 = dict(math=90,chinese=100,english=98,PE=95)
print(score1["chinese"]) #根据key获取语文成绩:100
if "PE" in score1: #判断字典中是否包含"PE"的key
print(score1["PE"]) #得到体育成绩:95
#获取所有的key并保存于列表中,输出结果:['math', 'chinese', 'english', 'PE']
print(score1.keys())
#获取所有的value并保存于列表中,输出结果:[90, 100, 98, 95]
print(score1.values())
#获取key和value对转化为列表
#输出结果:[('math', 90), ('chinese', 100), ('english', 98), ('PE', 95)]
print(score1.items())
字典和列表、元组有很大不同,正因为字典存储数据是没有顺序性的,它是使用“键”(key)查询“值”(value)的,所以适用于序列类型的“切片”运算在字典中无法使用。
字典的基础操作
字典中的“键”必须是唯一的,而“值”可以有相同值,字典中如果有相同的“键”却被设置为不同的“值”,那么只有最后面的“键”所对应的“值”有效。
元组(tuple)
元组(tuple)是有序对象,类似列表(list),差别在于元组是不可变对象,一旦创建之后,元组中的元素不能任意更改其位置,也不能更改其内容值。
通常,元组用于表示特定的概念,如坐标、矩形区域等。
sex1 = ("male","female") #使用括号生成并初始化元组
sex2 = tuple(["male","female"]) #从列表初始化
sex3 = ("male",) #只有一个元素时,后面也要加逗号
sex4 = "male","female" #默认是元组类型("male","female")
- 元组中元素的访问方法和列表一样,都可以使用下标和切片。
- 圆括号(( ))表示元组,方括号([ ])代表列表,大括号({ })代表字典。
- 初始化只包含一个元素的元组时,也必须在元素后加上逗号,如sex3。
- 直接用逗号分隔多个元素的赋值默认是元组,如变量sex4。
- 元组内的数据一旦被初始化,就不能更改。
创建元组
元组是一串由逗号分隔的值,可以用括号“()”创建元组对象,也可以用逗号“,”创建元组对象,如下所示:
fruitlist = ("Apple", "Orange", "Lemon")
fruitlist = "Apple", "Orange", "Lemon"
上面两条程序语句都是创建元组对象:(“Apple”,”Orange”,”Lemon”),如果元组对象中只有一个元素,仍必须在这个元素之后加上逗号,例如:
fruitlist = ("Apple")
元组可以存放不同数据类型的元素。元组中元素的下标编号从左到右是从[0]
开始的,从右到左则是从[-1]
开始的。列表是以中括号“[]”来存放元素的,而元组是以小括号“()”来存放元素的。
因为元组内的元素有对应的下标编号,所以可以使用for循环或while循环来读取元组内的元素。例如,以下程序语句用for循环将元组中的元素输出,其中len()函数可以求取元组的长度:
虽然在元组内的元素不可以用“[]”运算符来改变元素的值,不过元组内的元素仍然可以使用“+”“*”
运算符执行一些其他运算。使用“+”运算符可以将两个元组的数据内容串接成一个新的元组,而使用“*”运算符可以把元组的元素复制成多个。
解包与交换
元组是不可变对象,不可以直接修改元组元素的值,因此在列表中像append()、insert()等会改变元素个数或元素值的方法,都不能用于元组。而像count()用来统计元素出现的次数,或index()用来读取某元素第一次出现的下标值等,就可以用于元组。
Python针对元组有一个很特别的用法解包(Unpacking)。举例来说,下面的第1行程序语句将“Andy”“25”以及“上海”三个值定义为元组,第2行则使用变量读取元组中的元素值,这个操作就被称为Unpacking(解包):
datalist = ("Andy", "25", "上海") # Packing
name, age, addr= datalist # Unpacking
print(name) #输出 Andy
解包不只限于元组,包括列表和集合等序列对象,都可以用同样的方式来设置变量,序列解包等号左边的变量数量必须与等号右边的序列元素数量相同。
在其他程序设计语言中,如果想要交换(Swap)两个变量的值,通常需要第三个变量来辅助。 而在Python语言中,使用解包的特性,变量值的交换就变得非常简单,只需下面一行程序语句就可以达到交换的目的:
y,x = x,y
集合(set)
集合(set)与字典(dict)一样都是把元素放在大括号“{}”内,不过集合只有键(key)没有值(value),类似数学里的集合,可以对集合进行并集(|)、交集(&)、差集(-)与异或(^)等运算,集合中的元素具有无序和互异的特性。集合(set)有两个特点,一是集合内元素具有唯一性,二是集合内元素无序排列。有一个经常使用的经典用法,它最能体现集合的价值,那就是去除列表内重复的元素。
创建集合
集合可以使用大括号“{}”或调用set()方法来创建,使用大括号“{}”创建的方式如下:
fruitlist = {"Apple", "Orange", "Lemon"}
>>> a = set()
>>> a.update({'x','y','z'})
>>> a
{'x', 'y', 'z'}
>>> a.remove('z')
>>> a
{'x', 'y'}
>>> a.add('w')
>>> a
{'x', 'y', 'w'}
>>> a = {'A','D','B'}
>>> b = {'D','E','C'}
>>> a.difference(b) # 返回a有b没有的元素集合
{'B', 'A'}
>>> a - b # 记不住的话,这样写也行
{'B', 'A'}
>>> a.union(b) # 返回a和b的并集。虽然差集可以用a-b替代,但并集不能用a+b表示
{'C', 'B', 'A', 'D', 'E'}
>>> a.intersection(b) # 返回a和b重复元素的集合
{'D'}
>>> a.symmetric_difference(b) # 返回a和b非重复元素的集合
{'C', 'B', 'A', 'E'}
>>> list(set([1,2,5,2,3,4,5,'x',4,'x'])) # 去除数组 [1,2,5,2,3,4,5,'x',4,'x'] 中的重复元素
[1, 2, 3, 4, 5, 'x']
字符串
Python语言的文本处理功能非常强大,仅仅依赖字符串类的方法,就可以实现几乎所有的字符串操作。字符串对象还可以像列表那样索引和切片,但无法改变字符串对象的内容,这有点类似元组不可以增加、删除和修改元素。
>>> str(3.14) # 数字转字符串
'3.14'
>>> str(['a',1]) # 列表转字符串
"['a', 1]"
>>> str({'a':1, 'b':2}) # 字典转字符串
"{'a': 1, 'b': 2}"
>>> s = 'python真好用,very good.'
>>> s[1:-1] # 掐头去尾
'ython真好用,very good'
>>> s[::2] # 隔一个取一个元素
'pto真用 vr od'
>>> s[::-1] # 反转字符串
'.doog yrev,用好真nohtyp'
>>> s.upper() # 全部大写
'PYTHON真好用,VERY GOOD.'
>>> s.lower() # 全部小写
'python真好用,very good.'
>>> s.capitalize() # 字符串首字母大写
'Python真好用,very good.'
>>> s.title()
'Python真好用,Very Good.' # 单词首字母大写
>>> s.startswith('python') # 判断是否以指定的子串开头
True
>>> s.endswith('good.') # 判断是否以指定的子串结尾
True
>>> s.find('very') # 首次出现的索引,未找到则返回-1
10
>>> s.split() # 分割字符串,还可以指定分隔符
['python真好用,very', 'good.']
>>> s.replace('very', 'veryvery') # 替换子串
'python真好用,veryvery good.'
>>> '2345.6'.isdigit() # 判断是否是数字
False
>>> 'adS12K56'.isalpha() # 判断是否是字母
False
>>> 'adS12K56'.isalnum() # 判断是否是字母和数字
True
>>> '\t adS12K56 \n'.strip() # 去除首尾空格(包括制表位和换行符)
'adS12K56'