Python学习(3): 序列

序列是一种数据存储方式,用来存储一系列的数据。在内存中,序列就是一块用来存放 多个值的连续的内存空间。


由于 Python3 中一切皆对象,出序列中存储的是整数对象的地址,而不是整数对象的值。
python 中常用的序列结构有: 字符串、列表、元组、字典、集合

目录

列表

列表简介

列表的创建

基本语法[]创建

list()创建

range()创建整数列表

推导式生成列表

列表元素的增加和删除

append()方法

+运算符操作

extend()方法

insert()插入元素

乘法扩展

列表元素的删除

del 删除

pop()方法

remove()方法

列表元素访问和计数

通过索引直接访问元素

index()获得指定元素在列表中首次出现的索引

count()获得指定元素在列表中出现的次数

len()返回列表长度

成员资格判断

切片操作

列表的遍历

复制列表所有的元素到新列表对象

列表排序

修改原列表,不建新列表的排序

建新列表的排序

reversed()返回迭代器

列表相关的其他内置函数汇总

多维列表

二维列表

元组tuple

元组的创建

元组的元素访问和计数

zip

生成器推导式创建元组

元组总结

字典

字典的创建

字典元素的访问

字典元素添加、修改、删除

序列解包

表格数据使用字典和列表存储,并实现访问

字典核心底层原理(重要)

将一个键值对放进字典的底层过程

根据键查找“键值对”的底层过程

 集合

集合创建和删除

集合相关操作


列表

列表简介

 列表:用于存储任意数目、任意类型的数据集合。
列表是内置可变序列,是包含多个元素的有序连续的内存空间。列表定义的标准语法格式: a = [10,20,30,40]
其中,10,20,30,40 这些称为:列表a的元素。
列表中的元素可以各不相同,可以是任意类型。比如: a = [10,20,‘abc’,True]

 Python的列表大小可变,根据需要随时增加或缩小。
字符串和列表都是序列类型,一个字符串是一个字符序列,一个列表是任何元素的序列。

列表的创建



基本语法[]创建

a = [10,20,'wps','aaa'] 
a = [] #创建一个空的列表对象

list()创建

使用 list()可以将任何可迭代的数据转化成列表。

>>> a = list() #创建一个空的列表对象 
>>> a = list(range(10)) 
>>> a 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>> a = list("wps,aaa") 
>>> a ['w', 'p', 's',',', 'a', 'a', 'a']

range()创建整数列表

range()可以方便的创建整数列表,这在开发中极其有用。语法格式为: range([start,] end [,step])
start 参数:可选,表示起始数字。默认是 0
end参数:必选,表示结尾数字。
step参数:可选,表示步长,默认为1
python3 中 range()返回的是一个range 对象,而不是列表。通过list()方法将其转换成列表对象

>>> list(range(3,15,2)) 
[3, 5, 7, 9, 11, 13] 
>>> list(range(15,3,-1)) 
[15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4] 
>>> list(range(3,-10,-1))
[3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

推导式生成列表

使用列表推导式可以非常方便的创建列表,在开发中经常使用。但是,由于涉及到for 循环 和 if 语句。

>>> a = [x*2 for x in range(5)] #循环创建多个元素 
>>> a 
[0, 2, 4, 6, 8] 
>>> a = [x*2 for x in range(100) if x%9==0] #通过 if 过滤元素 
>>> a 
[0, 18, 36, 54, 72, 90, 108, 126, 144, 162, 180, 198]

列表元素的增加和删除

当列表增加和删除元素时,列表会自动进行内存管理,大大减少了程序员的负担。但这个特点涉及列表元素的大量移动,效率较低。除非必要,一般只在列表的尾部添加元素 或删除元素,这会大大提高列表的操作效率。

append()方法

原地修改列表对象,是真正的列表尾部添加新的元素,速度最快,推荐使用。

>>> a = [20,40] 
>>> a.append(80) 
>>> a 
[20, 40, 80]

+运算符操作

并不是真正的尾部添加元素,而是创建新的列表对象;将原列表的元素和新列表的元素依次复制到新的列表对象中。这样,会涉及大量的复制操作,对于操作大量元素不建议使用。

>>> a = [20,40] 
>>> id(a) 
46016072 
>>> a = a+[50] 
>>> id(a) 
46015432

变量a 的地址发生了变化。也就是创建了新的列表对象。





extend()方法

将目标列表的所有元素添加到本列表的尾部,属于原地操作,不创建新的列表对象。

>>> a = [20,40] 
>>> id(a) 
46016072 
>>> a.extend([50,60]) 
>>> id(a) 
46016072

insert()插入元素

使用insert()方法可以将指定的元素插入到列表对象的任意制定位置。这样会让插入位置后 面所有的元素进行移动,会影响处理速度。涉及大量元素时,尽量避免使用。类似发生这种 移动的函数还有:remove()、pop()、del(),它们在删除非尾部元素时也会发生操作位置后 面元素的移动。

>>> a = [10,20,30] 
>>> a.insert(2,100) 
>>> a 
[10, 20, 100, 30]

乘法扩展

使用乘法扩展列表,生成一个新列表,新列表元素时原列表元素的多次重复。
适用于乘法操作的,还有:字符串、元组。

列表元素的删除





del 删除

删除列表指定位置的元素。

>>> a = [100,200,888,300,400]
>>> del a[1]
>>> a
[100,200,300,400]

删除某一元素后,后面的元素一次向前拷贝。

pop()方法

 pop()删除并返回指定位置元素,如果未指定位置则默认操作列表最后一个元素。

>>> a = [10,20,30,40,50]
>>> a.pop()
50
>>> a
[10, 20, 30, 40]
>>> a.pop(1)
20
>>> a
[10, 30, 40]





remove()方法

删除首次出现的指定元素,若不存在该元素抛出异常。

>>> a = [10,20,30,40,50,20,30,20,30]
>>> a.remove(20)
>>> a
[10, 30, 40, 50, 20, 30, 20, 30]
>>> a.remove(100)
Traceback (most recent call last):
File "<pyshell#208>", line 1, in <module>
a.remove(100)
ValueError: list.remove(x): x not in list

列表元素访问和计数





通过索引直接访问元素

通过索引直接访问元素。索引的区间在[0, 列表长度-1]这个范围。超过这个范围则 会抛出异常。

index()获得指定元素在列表中首次出现的索引

index()可以获取指定元素首次出现的索引位置。语法是: index(value,[start,[end]])。其中, start 和end指定了搜索的范围。

>>> a = [10,20,30,40,50,20,30,20,30] 
>>> a.index(20) 
1 
>>> a.index(20,3) 
5 
>>> a.index(20,3) #从索引位置 3开始往后搜索的第一个 20 
5 
>>> a.index(30,5,7) #从索引位置5 到7这个区间,第一次出现 30元素的位置 
6

count()获得指定元素在列表中出现的次数





len()返回列表长度

len()返回列表长度,即列表中包含元素的个数。

成员资格判断

判断列表中是否存在指定的元素,可以使用 count()方法,返回0则表示不存在,返回 大于 0 则表示存在。但是,一般使用更加简洁的 in 关键字来判断,直接返回 True 或False。

切片操作

切片是Python序列及其重要的操作,适用于列表、元组、字符串等等。
切片的格式如下:切片 slice 操作可以让我们快速提取子列表或修改。
标准格式为: [起始偏移量start:终止偏移量end[:步长 step]]
注:当步长省略时顺便可以省略第二个冒号

 

 切片操作时,起始偏移量和终止偏移量不在[0,字符串长度-1]这个范围,也不会报错。起始 偏移量小于0则会当做 0,终止偏移量大于“长度-1”会被当成”长度-1”。

列表的遍历

for obj in listObj: 
	print(obj)

复制列表所有的元素到新列表对象

如下代码实现列表元素的复制了吗?

list1 = [30,40,50] 
list2 = list1 

只是将 list2 也指向了列表对象,也就是说 list2 和 list2 持有地址值是相同的,列表对象本 身的元素并没有复制。
通过如下简单方式,实现列表元素内容的复制:

list1 = [30,40,50] 
list2 = [] + list1

注:我们后面也会学习 copy模块,使用浅复制或深复制实现我们的复制操作





列表排序





修改原列表,不建新列表的排序

>>> a = [20,10,30,40] 
>>> id(a) 
46017416 
>>> a.sort() #默认是升序排列 
>>> a 
[10, 20, 30, 40] 
>>> a = [10,20,30,40] 
>>> a.sort(reverse=True) #降序排列 
>>> a 
[40, 30, 20, 10] 
>>> import random 
>>> random.shuffle(a) #打乱顺序 
>>> a 
[20, 40, 30, 10]

建新列表的排序

>>> a = [20,10,30,40] 
>>> id(a) 
46016008 
>>> a = sorted(a) #默认升序 
>>> a 
[10, 20, 30, 40] 
>>> id(a) 
45907848 
>>> a = [20,10,30,40] 
>>> id(a) 
45840584
>>> c = sorted(a,reverse=True) #降序 
>>> c 
[40, 30, 20, 10]

reversed()返回迭代器

内置函数reversed()也支持进行逆序排列,与列表对象 reverse()方法不同的是,内置函数 reversed()不对原列表做任何修改,只是返回一个逆序排列的迭代器对象。

>>> a = [20,10,30,40] 
>>> c = reversed(a) 
>>> c 
<list_reverseiterator object at 0x0000000002BCCEB8> 
>>> list(c) 
[40, 30, 10, 20] 
>>> list(c) 
[]

打印输出c发现提示是:list_reverseiterator。也就是一个迭代对象。同时,我们使用 list©进行输出,发现只能使用一次。第一次输出了元素,第二次为空。那是因为迭代对象 在第一次时已经遍历结束了,第二次不能再使用。

列表相关的其他内置函数汇总

max和min、sum





多维列表





二维列表

一维列表可以存储一维、线性的数据。
二维列表可以存储二维、表格的数据。

元组tuple

列表属于可变序列,可以任意修改列表中的元素。元组属于不可变序列,不能修改元组中的 元素。因此,元组没有增加元素、修改元素、删除元素相关的方法。
元组支持如 下操作:

  1. 索引访问
  2. 切片操作
  3. 连接操作
  4. 成员关系操作
  5. 比较运算操作
  6. 计数:元组长度len()、最大值 max()、最小值 min()、求和sum()等。

元组的创建

  1. 通过()创建元组。小括号可以省略。
    a = (10,20,30) 或者 a = 10,20,30
    如果元组只有一个元素,则必须后面加逗号。这是因为解释器会把(1)解释为整数 1, (1,) 解释为元组。
>>> a = (1) 
>>> type(a) 
<class 'int'> 
>>> a = (1,) #或者 a = 1, 
>>> type(a) 
<class 'tuple'> 

2.通过tuple()创建元组
   tuple(可迭代的对象)

b = tuple() #创建一个空元组对象
b = tuple("abc")
b = tuple(range(3))
b = tuple([2,3,4])

总结: tuple()可以接收列表、字符串、其他序列类型、迭代器等生成元组。 list()可以接收元组、字符串、其他序列类型、迭代器等生成列表。

元组的元素访问和计数

  1. 元组的元素不能修改
  2. 元组的元素访问和列表一样,只不过返回的仍然是元组对象。
  3. 列表关于排序的方法list.sorted()是修改原列表对象,元组没有该方法。如果要对元组排 序,只能使用内置函数 sorted(tupleObj),并生成新的列表对象。

zip

zip(列表 1,列表2,…)将多个列表对应位置的元素组合成为元组,并返回这个 zip对象。

>>> a = [10,20,30] 
>>> b = [40,50,60] 
>>> c = [70,80,90] 
>>> d = zip(a,b,c) 
>>> list(d) 
[(10, 40, 70), (20, 50, 80), (30, 60, 90)]

生成器推导式创建元组

从形式上看,生成器推导式与列表推导式类似,只是生成器推导式使用小括号。列表推 导式直接生成列表对象,生成器推导式生成的不是列表也不是元组,而是一个生成器对象。

通过生成器对象,转化成列表或者元组。也可以使用生成器对象的__next__() 方法进行遍历,或者直接作为迭代器对象来使用。不管什么方式使用,元素访问结束后,如 果需要重新访问其中的元素,必须重新创建该生成器对象。

>>> s = (x*2 for x in range(5)) 
>>> s 
<generator object <genexpr> at 0x0000000002BDEB48> 
>>> tuple(s) 
(0, 2, 4, 6, 8) 
>>> list(s) #只能访问一次元素。第二次就为空了。需要再生成一次 [] 
>>> s 
<generator object <genexpr> at 0x0000000002BDEB48> 
>>> tuple(s) 
() 
>>> s = (x*2 for x in range(5)) 
>>> s.__next__() 
0 
>>> s.__next__() 
2 
>>> s.__next__() 
4

元组总结

  1. 元组的核心特点是:不可变序列。
  2. 元组的访问和处理速度比列表快。
  3. 与整数和字符串一样,元组可以作为字典的键,列表则永远不能作为字典的键使用。

字典

字典是“键值对”的无序可变序列,字典中的每个元素都是一个“键值对”,包含:“键 对象”和“值对象”。可以通过“键对象”实现快速获取、删除、更新对应的“值对象”。
列表中通过“下标数字”找到对应的对象。字典中通过“键对象”找到对应的“值 对象”。“键”是任意的不可变数据,比如:整数、浮点数、字符串、元组。但是:列表、 字典、集合这些可变对象,不能作为“键”。并且“键”不可重复。
“值”可以是任意的数据,并且可重复。
一个典型的字典的定义方式: a = {‘name’:‘wps’,‘age’:18,‘job’:‘programmer’}

字典的创建

1.可以通过{}、dict()来创建字典对象。

>>> a = {'name':'wps','age':18,'job':'programmer'} 
>>> b = dict(name='wps',age=18,job='programmer') 
>>> a = dict([("name","wps"),("age",18)]) 
>>> c = {} #空的字典对象 
>>> d = dict() #空的字典对象

2.通过zip()创建字典对象

>>> k = ['name','age','job'] 
>>> v = ['wps',18,'techer'] 
>>> d = dict(zip(k,v)) 
>>> d {'name': 'wps', 'age': 18, 'job': 'techer'}

3.通过fromkeys创建值为空的字典

>>> a = dict.fromkeys(['name','age','job']) 
>>> a {'name': None, 'age': None, 'job': None}

字典元素的访问

1.通过 [键] 获得“值”。若键不存在,则抛出异常。

>>> a = {'name':'wps','age':18,'job':'programmer'}  
>>> a['age'] 
18 
>>> a['sex'] 
Traceback (most recent call last): File "<pyshell#374>", line 1, in <module> a['sex'] KeyError: 'sex'

2.通过get()方法获得“值”。推荐使用。优点是:指定键不存在,返回None;也可以设 定指定键不存在时默认返回的对象。推荐使用 get()获取“值对象”。

>>> a.get('name') 
'wps' 
>>> a.get('sex') 
>>> a.get('sex','一个男人') 
'一个男人'

3.列出所有的键值对

>>> a.items() 
dict_items([('name', 'wps'), ('age', 18), ('job', 'programmer')])

5.len() 键值对的个数
6.检测一个“键”是否在字典中

>>> a = {"name":"wps","age":18} 
>>> "name" in a 
True

字典元素添加、修改、删除

1.给字典新增“键值对”。如果“键”已经存在,则覆盖旧的键值对;如果“键”不存在, 则新增“键值对”。
2.使用update()将新字典中所有键值对全部添加到旧字典对象上。如果key有重复,则直 接覆盖。
3.字典中元素的删除,可以使用del()方法;或者 clear()删除所有键值对;pop()删除指定 键值对,并返回对应的“值对象”;
4.popitem() :随机删除和返回该键值对。字典是“无序可变序列”,因此没有第一个元 素、最后一个元素的概念;popitem 弹出随机的项,因为字典并没有"最后的元素"或者其 他有关顺序的概念。若想一个接一个地移除并处理项,这个方法就非常有效(因为不用首先获取键的列表)。
 

序列解包

序列解包可以用于元组、列表、字典。序列解包可以方便的对多个变量赋值。

>>> (a,b,c)=(9,8,10) 
>>> a 
9 
>>> [a,b,c]=[10,20,30] 
>>> a 
10 
>>> b 
20

序列解包用于字典时,默认是对“键”进行操作; 如果需要对键值对操作,则需要使用 items();如果需要对“值”进行操作,则需要使用 values();

>>> s = {'name':'wps','age':18,'job':'teacher'} 
>>> name,age,job=s #默认对键进行操作 
>>> name
'name' 
>>> name,age,job=s.items() #对键值对进行操作 
>>> name 
('name', 'wps') 
>>> name,age,job=s.values() #对值进行操作 
>>> name 
'wps'

表格数据使用字典和列表存储,并实现访问

r1 = {"name":"王小一","age":16,"salary":10000,"city":"北京"}
r2 = {"name":"王小二","age":17,"salary":20000,"city":"河北"}
r3 = {"name":"王小三","age":18,"salary":30000,"city":"上海"}

tb = [r1,r2,r3]

#获得第二行的人的薪资
print(tb[1].get("salary"))

#打印表中所有的薪资
for i in range(len(tb)):
    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("cit"))

字典核心底层原理(重要)

字典对象的核心是散列表。散列表是一个稀疏数组(总是有空白元素的数组),数组的 每个单元叫做 bucket。每个 bucket 有两部分:一个是键对象的引用,一个是值对象的引 用。
由于,所有bucket 结构和大小一致,可以通过偏移量来读取指定 bucket。

将一个键值对放进字典的底层过程

假设字典 a对象创建完后,数组长度为 8,键值对放到字典对象 a 中,首先第一步需要计算 键”name”的散列值。Python 中可以通过hash()来计算。

>>> bin(hash("name")) 
'-0b1010111101001110110101100100101'

由于数组长度为 8,我们可以拿计算出的散列值的最右边 3 位数字作为偏移量,即 “101”,十进制是数字 5。我们查看偏移量 5,对应的 bucket 是否为空。如果为空,则 将键值对放进去。如果不为空,则依次取右边 3位作为偏移量,即“100”,十进制是数字4。再查看偏移量为 4 的 bucket 是否为空。直到找到为空的 bucket 将键值对放进去。

扩容
python会根据散列表的拥挤程度扩容。“扩容”指的是:创造更大的数组,将原有内容 拷贝到新数组中。 接近 2/3 时,数组就会扩容。

根据键查找“键值对”的底层过程

当我们调用a.get(“name”),就是根据键“name”查找到“键值对”,从而找到值 对象值。
第一步,我们仍然要计算“name”对象的散列值:

>>> bin(hash("name")) 
'-0b1010111101001110110101100100101'

 和存储的底层流程算法一致,也是依次取散列值的不同位置的数字。 假设数组长度为 8,可以拿计算出的散列值的最右边 3位数字作为偏移量,即“101”,十进制是数字 5。我们查看偏移量 5,对应的bucket 是否为空。如果为空,则返回None。如果不为空, 则将这个bucket的键对象计算对应散列值,和散列值进行比较,如果相等。则将对 应“值对象”返回。如果不相等,则再依次取其他几位数字,重新计算偏移量。依次取完后, 仍然没有找到。则返回 None。

用法总结

1.键必须可散列
        (1) 数字、字符串、元组,都是可散列的。
        (2) 自定义对象需要支持下面三点:
                ①支持 hash()函数
                ②支持通过__eq__()方法检测相等性。
                ③若a==b为真,则 hash(a)==hash(b)也为真。
2.字典在内存中开销巨大,典型的空间换时间。
3.键查询速度很快
4.往字典里面添加新建可能导致扩容,导致散列表中键的次序变化。因此,不要在遍历字典的同时进行字典的修改。

 集合

集合是无序可变,元素不能重复。实际上,集合底层是字典实现,集合的所有元素都是字典 中的“键对象”,因此是不能重复的且唯一的。

集合创建和删除

使用{}创建集合对象,并使用 add()方法添加元素。
使用set(),将列表、元组等可迭代对象转成集合。如果原来数据存在重复数据,则只保 留一个。
remove()删除指定元素;clear()清空整个集合

集合相关操作

像数学中概念一样,Python对集合也提供了并集、交集、差集等运算。
 

>>> a = {1,3,'wps'} 
>>> b = {'he','it','wps'} 
>>> a|b #并集 
{1, 3, 'wps', 'he', 'it'} 
>>> a&b #交集 
{'wps'} 
>>> a-b #差集 
{1, 3} 
>>> a.union(b) #并集 
{1, 3, 'wps', 'he', 'it'} 
>>> a.intersection(b) #交集 
{'wps'} 
>>> a.difference(b) #差集 
{1, 3}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值