序列是一种数据存储方式,用来存储一系列的数据。在内存中,序列就是一块用来存放多个值的连续空间。比如一个整数序列:[10,20,30,40]。可以这样表示:
由于Python3中一切皆对象,在内存中实际是按照如下方式储存的:
a=[10,20,30,40]
从图示中我们可以看出,序列中存储的是整数对象的地址,而不是整数对象的值。
Python3常用的序列对象有:
字符串、元组、列表、字典、集合
列表:用于存储任意数目、任意类型的数据集合。
列表是内置可变序列,包含多个元素的有序连续的内存空间。
列表的标准语法格式:a=[10,20,30,40]
其中,10,20,30,40这些称为:列表a的元素。
列表中的元素可以各不相同,可以是任意类型。比如:a=[10,'20','abc',True]
列表对象常用方法如下:
方法 | 要点 | 描述 |
---|---|---|
list.append(x) | 增加元素 | 将元素x增加到列表list尾部 |
list.extend(alist) | 增加元素 | 将列表alist所有元素加到列表list尾部 |
list.insert(index,x) | 增加元素 | 将列表list指定位置index处插入元素 |
list.remove(x) | 删除元素 | 将列表list中删除首次出现的指定元素x,若不存在该元素则抛出异常 |
list.pop([index]) | 删除元素 | 删除并返回列表list指定为止index处的元素,默认是最后一个元素 |
list.clear() | 删除所有元素 | 删除列表list中所有元素,并不是删除该列表对象 |
list.index(x) | 访问元素 | 返回第一个x在列表list的索引位置,若不存在x元素抛出异常 |
list.count(x) | 计数 | 返回指定元素x在列表list中出现的次数 |
len(list) | 列表长度 | 返回列表list中包含元素的个数 |
list.reserse() | 翻转列表 | 所有元素原地翻转 |
list.sort() | 排序 | 所有元素原地排序 |
list.copy() | 浅拷贝 | 返回列表对象的浅拷贝 |
Python的列表大小可变,根据需要随时增加或缩小。
字符串和列表都是序列类型,一个字符串是一个字符序列,一个列表是任何元素的序列。在字符串中的很多方法,在列表中也有类似的用法,几乎一模一样。
使用list()可以将任何可迭代的数据类型装换为列表。
range()可以帮助我们非常方便的创建整数列表,这个在开发中极具作用。语法格式为:
range([start,] end [,step])
start参数:可选,表示起始数字。默认是0
end参数:必选,表示结尾数字(不包括该数字,左闭右开)
step参数:可选,表示步长,默认为1
Python3中range()返回的是一个range对象,而不是列表。我们需要通过list()方法将其转换成列表对象。
使用推导式可以非常方便的创建列表,在开发中经常使用,需要涉及到for和if语句。
当列表增加和删除元素是,列表会自动进行内存管理,大大减少了程序员的负担,但这个特点设计列表元素的大量移动,效率较低。除非必要我们一般只在列表的尾部添加元素或删除元素,这样会大大提高变成效率。
原地修改列表对象,真正在列表尾部添加新的元素,速度最快,推荐使用。
此方法不创建新的对象!
并不是真正的尾部添加元素,而是创建新的列表对象;将原列表的元素的新列表的元素依次复制到新的列表中。这样,会涉及大量的复制操作,对于操作大量元素不建议使用。
通过如上测试,我们发现变量a的地址发生了变化。也就是创建了新的列表对象。
将目标列表的所有元素添加到原列表的尾部,属于原地操作,不创建新的列表对象。
使用insert()方法可以将指定位置元素插入到列表对象的任意指定位置。这样会让插入位置后面所有的元素进行移动,会影响处理速度。设计大量元素移动是,尽量表面使用。
list.insert(index,x)
在列表list的index位置处插入元素x
注:指定位置index既可以正向搜索,也可以反向搜索。
index >= len(list),此时是在队尾插入;
index < -len(list),此时是在队头插入。
类似发生这种移动的函数还有remove()、pop()、del()。它们在删除非尾部元素时也会发生操作位置后面元素的移动。
使用乘法扩展列表,生成一个新列表,新列表元素为原列表的多次重复,返回该新列表。
适用于乘法扩展的,还有字符串、元组等。
del list[index]
删除原列表中指定位置的元素。
注:index可以是正向搜索,也可以是反向搜索,但要求index合法,否者抛出异常。
pop()删除院原列表指定位置元素,如果未指定则默认操作列表最后一个元素,返回被删除的元素。指定位置同样既可以正向搜索,也可以反向搜索,要求合法,否者抛出异常。
删除首次出现的指定元素,若该元素不存在则抛出异常。
remove()方法没有返回值!!!即返回的是None
我们可以直接通过索引直接访问元素。索引的区间长度在[0,列表长度-1]或[-列表长度,-1]这个范围。超过这个范围则会抛出异常。
index()可以获得指定元素在列表中首次出现的索引。若指定元素不出现则抛出异常。
语法是:index(value,[start,[end]])
其中start和end指定了搜索的范围,遵循着左闭右开的原则,[start,end)。
注:搜索范围同样可以正向搜索,也可以反向搜索。
count()可以返回指定元素在列表中出现的次数。
判断列表中是否存在指定的元素,我们可以使用count()方法,返回0则表示不存在,返回大于0则表示存在。但是,一般我们会使用更简洁的in关键字来判断,直接返回True或False。
列表的切片操作和字符串类似。
切片slice操作可以让我们快速提取子列表或修改。标准格式为:
[起始偏移量start:终止偏移量end[:步长]]
注:当步长省略时数遍你可以省略第二个冒号。左闭右开,也可以说是包头不包尾。
典型操作(三个数为正数):
操作和说明 | 示例 | 结果 |
---|---|---|
[:] 提取整个列表 |
[10,20,30][:]
|
[10, 20, 30] |
[start:]从start索引开始直到结尾 | [10,20,30][1:] | [20,30] |
[:end]从头开始直到end-1 | [10, 20, 30][:2] | [10, 20] |
[start:end]从start开始直到end-1 | [10,20,30,40][1:3] | [20,30] |
[start:end:step]从start提取到end-1,步长是step | [10,20,30,40,50,60][1:6:2] | [20, 40, 60] |
其它操作(三个量为负数)的情况:
示例 | 说明 | 结果 |
---|---|---|
[10,20,30,40,50,60,70][-3:]
|
倒数第三个 | [50, 60, 70] |
[10,20,30,40,50,60,70][-5:-3] | 倒数第五个到倒数第四个 (包头不包尾) |
[30, 40] |
[10,20,30,40,50,60,70][::-1]
|
步长为负,从右到左反向提取 | [70, 60, 50, 40, 30, 20, 10] |
切片操作时,起始偏移量和终止偏移量不在[0:字符串长度]这个范围,也不会报错。起始偏移量小于0则会被当作0,终止偏移量大于“长度”会被当成“长度”。例如:
如下代码是否实现列表元素复制?
list1=[30,40,50]
list2=list1
只是将list2也指向了list1指向的对象,也就是说list1和list2持有地址值是相同的,列表元素本身并没有复制。
可以通过如下简单方式,实现列表元素内容的复制:
list1=[30,40,50,60]
list2=[]+list1
还可以使用copy模块,使用浅复制或深复制实现复制操作。
使用sort()方法,修改原列表,不新建列表的排序。sort()方法无返回值。
通过使用内置函数sorted()进行排序,这个方法返回新列表,不对原列表进行修改。
通过上面操作,可以看出生成的列表对象b和c都是完全新的列表对象。
内置函数reversed()也支持逆序排序吗,与列表对象reverse()方法不同的是,内置函数reversed()不对原列表做任何修改,只是返回一个逆序列表的迭代器对象。
用于返回列表中的最大值和最小值
对数值型列表的所有元素进行求和操作,对非数值列表则会报错。
一维列表可以帮助我们存储一维、线性的数据。
二维列表可以帮助我们存储而二维、表格的数据。
例如下表的数据:
姓名 | 年龄 | 薪资 | 城市 |
---|---|---|---|
高小一 | 18 | 30000 | 北京 |
高小二 | 19 | 20000 | 上海 |
高小三 | 20 | 10000 | 深圳 |
源码:
a=[
["高小一",18,30000,"北京"],
["高小二",19,20000,"上海"],
["高小一",20,10000,"深圳"]
]
内存结构图:
列表属于可变序列,可以任意修改列表中的元素。元组属于不可变序列,不能修改元组中的元素。因此,元组没有增加元素、修改元素、删除元素相关的方法。
在元组中重点掌握元组的创建和删除,元组中元素的访问和计数即可。
元组支持以下操作:
1.索引访问
2.切片操作
3.连接操作
4.成员关系操作
5.比较运算操作
6.计数:元组长度len()、最大值max()、最小值min()、求和sum()等。
1.通过()创建元组。小括号可以省去。
a=(10,20,30) 或者 a= 10,20,30
如果元组只有一个元素,则必须后面加逗号。这时因为解释器会把(1)解释我整数1,(1,)解释为元组。
2.通过tuple()创建元组
tuple(可迭代的对象)
例如:
总结:
tuple()可以接受列表、字符串、其他序列类型、迭代器等生成组。
list()可以接受元组、字符串、其他序列类型、迭代器生成列表。
1.元组的元素不能修改
2.元组的元素访问和列表一样,只不过返回的依然是元组对象。
3.列表关于排序的方法list.sort()是修改原列表对象,元组没有该方法。如果要对元组排序,只能使用内置函数sorted(tupleObj),并生成新的列表对象。
zip(列表1,列表2,……)将多个列表对应位置的元素组合成为元组,并返回这个zip对象。
从形式上看,生成器推导和列表推导类似,只是生成器推导式使用小括号。列表推导式直接生成列表对象,生成器推导式生成的不是列表也不是元组,而是一个生成器对象。
我们可以通过生成器对象,转化成列表或者元组。也可以使用生成器对象_next_()方法进行遍历,或者直接作为迭代器对象来使用。不管什么方式使用,元素访问结束后,如果需要重新访问其中元素,必须重新创建生成器对象。
生成器使用测试:
1.元组的核心是不可变序列。
2.元组的访问和处理速度比列表快。
3.与整数和字符串一样,元组可以作为字典的键,列表则永远不能作为字典的键使用。
字典是“键值对”的无序可变序列,字典中的每一元素都是一个“键值对”,包含:“键对象”和“值对象”。我们可以通过“键对象”实现快速获取、删除、更新对应的“值对象”。
列表中我们通过“下标数字”找到对应的对象。字典中通过“键对象”找到对应的“值对象”。“键”是任意不可变数据类型,比如:整数、浮点数、字符串、元组。但是:列表、字典、集合这些可变对象,不能作为“键”。并且“键”不可重复。
一个典型的字典的定义方式:
a={'name':'phh','age':18,'job':'programmer'}
1.我们可以通过{}、dict()来创建字典对象。
2.通过zip()创建字典对象
3.通过fromkeys创建值为空的字典
为了测试各种访问方法,我们这里设定一个字典对象:
a={'name':'phh','age':18,'job':'programmer'}
1.通过 [键] 获得 “值”。若键不存在,则抛出异常。
2.通过get()方法获得“值”。推荐使用。优点是:指定键不存在,返回None;也可以设定指定键不存在是默认返回的对象。推荐使用get()获取“值对象”。
3.列出所有的键值对
4.列出所有的键,列出所有的值。
5.len() 键值的数目
6.检测一个“键”是否在字典中。
1.给字典新增“键值对”。
如果“键”已经存在,则覆盖旧的键值对;如果“键”不存在,则新增“键值对”。
2.如果使用update()将字典中所有键值对全图添加到旧字典上。如果key值有重复,则直接覆盖。
3.字典中元素的删除,可以使用del()方法;或者使用clear()删除所有键值对;pop()删除指定键值对,并返回对应的“值对象”。
4.popitem()随机删除和返回该键值对。字典是“无序可变序列”,因此没有第一个元素、最后一个元素的概念;popitem弹出随机的项,因为字典并没有“最后的元素”或则其它有关顺序的概念。若想一个接一个地移除处理项,这个方法就非常有效(因为不用获取键的列表)。
序列解包可以用于元组、列表、字典。序列解可以让我们方便对多个变量赋值。
序列解包用于字典时,默认是对'“键”进行操作;如果需要对键值进行操作,则需要使用items();如果需要对“值”进行操作,则需要使用values()。
源代码:
r1 = {"name":"高小一","age":18,"salary":30000,"city":"北京"}
r2 = {"name":"高小二","age":19,"salary":20000,"city":"上海"}
r3 = {"name":"高小五","age":20,"salary":10000,"city":"深圳"}
tb = [r1,r2,r3]
#获得第二行的人的薪资
print(tb[1].get("salary"))
#打印表中所有的的薪资
for i in range(len(tb)): # i -->0,1,2
print(tb[i].get("salary"))
#打印表的所有数据
for i in range(len(tb)):
print(tb[i].get("name"),tb[i].get("age"),tb[i].get("salary"),tb[i].get("city"))
字典的核心是散列表。散列表是一个稀疏数组(总是有空白的数组),数组的每个单元叫做bucket有两部分:一个是键对象的引用,一个是值对象的引用。
由于,所有bucket结构和大小一致,我们可以通过偏移量来读取指定
明白一个键值对是如何存储到数组中,根据键对象取到值对象,理解起来就简单了。
当我们a.get('name'),就是根据键‘name'查找到“键值对”,从而找到值对象'phh'。
第一步,计算‘name’对象的散列值:
用法总结:
1.键必须可散列
(1) 数字、字符串、元组,都是可散列的。
(2) 自定义对象需要支持下面三点:
支持hash()函数
支持通过__eq__()方法检测相等性。
若a==b为真,则hash(a)==hash(b)为真。
2.字典在内存中开销巨大,典型的空间换时间。
3.键查询速度很快。
4.往字典添加新键可能导致扩容,导致散列中键的次序变化。因此,不要在遍历字典的同时进行字典的修改。
集合是无序可变,元素不能重复。实际上,集合底层是字典实现,集合所有元素都是字典中的“键对象”,因此是不能重复且唯一的。
1.使用{}创建对象,并使用add()方法添加元素。
在使用add()方法时,添加已经存在集合中元素不会抛出异常。
2.使用set(),将列表、元组等可迭代对象转为集合。如果原数据存在重复数据,则值保留一个。
3.remove()删除指定元素;clear()清空整个集合。
像数学中概念一样,Python对集合也提供了并集、交集、差集等运算。