Python培训
400-996-5531
内置据结构大总结 今天不讲解新的内容,主要回顾一下以往讲过的内置数据结构,来个大总结。
五种线性结构
列表
元组
字符串
bytes
bytearray
两种非线性结构
字典
集合
列表、元组、字符串属于线性结构,我们可以对其进行切片操作、解包/封包操作。
序列类型操作符
下表是所有序列类型都适用的操作符:
序列操作符作用
seq[ind]获得下标为ind的元素
seq[ind1:ind2]获得下标从ind1到ind2间的元素集合
seq * expr序列重复expr次
seq1 + seq2连接序列seq1和seq2
obj in seq判断obj元素是否包含在seq中
obj not in判断obj元素是否不包含在seq中
几种数据结构的共性
这几种数据结构的共性:
都是顺序存储
顺序访问
可迭代对象(可迭代对象可以用len方法获取其长度)
通过索引进行元素的访问
可以进行切片操作
切片
切片不会对原有的序列做任何修改,切片的语法为:
seq[start:stop]
从索引start开始,到索引stop结束,不包含stop,返回新的序列,不会对原有的对象做任何修改。
几个特性:
start超出索引范围:start = 0
stop超出索引范围:stop = -1
负数索引:实际上可转化为:len(seq) + index
当start >= stop时,返回空列表
slice的实现:
lst = list(range(0, 10))def slice(lst, start=0, stop=0): if start < 0: start = len(lst) + start if stop <= 0: stop = len(lst) + stop if stop <= start: return [] if stop > len(lst): stop = len(lst) if start < 0: start = 0 ret = [] for i, v in enumerate(lst): if i >= start and i < stop: ret.append(v) return retprint(slice(lst, 3, 2))print(slice(lst, 2, 5))print(slice(lst, -100, 100))
运行结果为:
: [] : [2, 3, 4] : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
如果有了步长之后,上面的规则就会发生变化。接下来加入步长的slice实现:
def slice(lst, start=0, stop=0, step=1): ret = [] if stop < 0: tmp = start start = tmp stop = start current = start while current < stop: try: ret.append(lst[current]) except IndexError: pass current += step return ret
切片的一些常用操作:
>>> lst = list(range(0, 10))>>> lst[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> lst[:] # 等效于copy方法>>> lst[-5:-3] # 支持负数索引# start大于等于stop时,返回空列表>>> lst[3:1]# 列出偶数,步长为2lst[::2][0, 2, 4, 6, 8]# 列出偶数,步长为2,并倒序输出lst[::2][::-1][8, 6, 4, 2, 0]# 列出奇数,步长为2,并倒序输出lst[::-2][9, 7, 5, 3, 1]# 列出偶数,步长为2,并倒序输出lst[-2::-2][8, 6, 4, 2, 0]
索引
如果索引超出范围,将引发IndexError的异常。修改元素的时候,如果超出索引范围,也同样引发IndexError异常。
index(value)方法根据value找索引
count(value)方法统计value出现的次数
enumerate的实现:
def enumerate(iterator): i = 0 for v in iterator: yield i, v i += 1def enumerate(iterator): ret = [] i = 0 for v in iterator: ret.append((i, v)) i += 1 return ret
引用
列表批量赋值:
## 当赋值的序列连续时# 对切片赋值,会替代原来的元素>>> lst = list(range(0, 10))>>> lst[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> lst[3:5] = ['x', 'y', 'z']>>> lst[0, 1, 2, 'x', 'y', 'z', 5, 6, 7, 8, 9]>>> lst = list(range(0, 10))>>> lst[3:5] = ['x']>>> lst[0, 1, 2, 'x', 5, 6, 7, 8, 9]>>> lst = list(range(0, 10))>>> lst[3:5] = 'x'>>> lst[0, 1, 2, 'x', 5, 6, 7, 8, 9]## 当赋值的序列不连续时>>> lst = list(range(0, 10))>>> lst[3:8:2] = ['x', 'y', 'z']>>> lst[0, 1, 2, 'x', 4, 'y', 6, 'z', 8, 9]>>> lst = list(range(0, 10))>>> lst[3:8:2] = ['x']ValueError: attempt to assign sequence of size 1 to extended slice of size 3>>> lst[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
不建议使用以上的方式对切片赋值的操作。
解包/封包
解构与封装可以叫做解包与封包。
解构把集合里的元素复制给变量;
封装是用变量构建元组。
解构:按照元素顺序,把线性解构的元素依次赋值给变量。
封装的例子:
t = 1, 2print(t)(1, 2)print(type(t))<class 'tuple'>
定义一个元组,可以省略小括号。
t1 = (1, 2)t2 = 1, 2print(t1 == t2) # t1与t2是等效的True
封装出来的是元组。封装没有什么难度。解构的变化多样,接下来重点看看解构。
先看一个例子:
In[29]: def swap(a, b): ...: i = a ...: a = b ...: b = i ...: return (a, b) ...: In[30]: swap(1, 3)Out[30]: (3, 1)
对上面的代码进行改写,由3行代码,变成了一行代码:
In[31]: def swap(a, b): ...: a, b = b, a ...: return (a, b) ...: In[32]: swap(1, 3)Out[32]: (3, 1)
对于如下的代码操作,就是解包:
In[33]: x, y = (1, 3)In[34]: xOut[34]: 1In[35]: yOut[35]: 3
上面的代码使用的是元组,列表也是可以的:
In[36]: a, b = 1, 3In[37]: aOut[37]: 1In[38]: bOut[38]: 3
接下来看一下封包:
In[39]: t = 1, 3In[40]: tOut[40]: (1, 3)In[41]: type(t)Out[41]: tuple
继续看例子:
In[42]: head, tail = list(range(0, 10))# 将会得到如下的错误,因为=两边的元素数量不一致导致的ValueError: too many values to unpack (expected 2)In[43]: head, *tail = list(range(0, 10))In[44]: headOut[44]: 0In[45]: tailOut[45]: [1, 2, 3, 4, 5, 6, 7, 8, 9]In[46]: *head, tail = list(range(0, 10))In[47]: headOut[47]: [0, 1, 2, 3, 4, 5, 6, 7, 8]In[48]: tailOut[48]: 9
如果对一个含有2个元素的列表进行解包:
In[49]: head, *tail = [1, 2]In[50]: headOut[50]: 1In[51]: tailOut[51]: [2]
如果对一个含有一个元素的列表进行解包:
In[52]: head, *tail = [1]In[53]: headOut[53]: 1In[54]: tailOut[54]: []
如果对一个空列表进行解包:
In[55]: head, *tail = []ValueError: not enough values to unpack (expected at least 1, got 0)
针对上述例子的总结:
左边不能只有一个星号,还要有其他元素
如果左边不用星号,那么左边的元素个数要与右边的元素个数相同
左边变量数小于右边元素个数,且左边没有加星号会报错
元素按照顺序赋值给变量
变量和元素必须匹配
加星号变量,可以接收任意个数的元素
加星号的变量不能单独出现
针对上述,写一个具体的例子:
def it(lst): if lst: head, *tail = lst print(head) it(tail)it(list(range(0, 10)))0123456789
更复杂一点的例子:
In[63]: head, *tail = [1, 2, 3]In[64]: headOut[64]: 1In[65]: tailOut[65]: [2, 3]
下面这个例子,在Python2中不能实现:
In[59]: head, *mid, tail = [1, 2, 3, 4, 5]In[60]: headOut[60]: 1In[61]: midOut[61]: [2, 3, 4]In[62]: tailOut[62]: 5
接下来还有更好远的,如果我们要丢弃=右边某个值,可以使用下划线来,演示如下:
In[66]: lst = list(range(0, 10))In[67]: lstOut[67]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]In[68]: a, b, _, c, *_ = lstIn[69]: aOut[69]: 0In[70]: bOut[70]: 1In[71]: cOut[71]: 3
如果我们只想要序列的首位两个元素,可以这样操作:
In[72]: head, *_, tail = lstIn[73]: headOut[73]: 0In[74]: tailOut[74]: 9
再来一发,两边结构要一样:
In[75]: lst = [1, [2, 3], 4]In[76]: a, (b, c), d = lstIn[77]: aOut[77]: 1In[78]: bOut[78]: 2In[79]: cOut[79]: 3In[80]: dOut[80]: 4
对上面的例子,再来稍微变化一下,不过两边的结构要一样,解构是支持多层次的。:
In[81]: lst = [1, [2, 3, 4, 5, 6, 8], 9]In[82]: lstOut[82]: [1, [2, 3, 4, 5, 6, 8], 9]In[83]: a, (b, *_, c), d = lstIn[84]: aOut[84]: 1In[85]: bOut[85]: 2In[86]: cOut[86]: 8In[87]: dOut[87]: 9
注意:
解包的时候,两边的结构要一致 (重要的事情说三遍)
解包的时候,两边的结构要一致 (重要的事情说三遍)
解包的时候,两边的结构要一致 (重要的事情说三遍)
只要两边结构一样就行
>>> a, (b, (c, (d,))) = [1, [2, [3, [4]]]]>>> a1>>> b2>>> c3>>> d4
python的一个惯例,使用单个下划线表示丢弃该变量。单个下划线也是Python合法的标识符,但是如果不是要丢弃一个变量,通常不要用单个下划线表示一个有意义的变量。
head, *_ = 'I love python'print(head)Ikey, *_, value = 'env = properties'.partition('=')print(key)envprint(value)properties
非常复杂的数据结构,多层嵌套的线性结构的时候,可以用解构快速提取其中的值。
填写下面表单即可预约申请免费试听! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!
Copyright © 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有
Tedu.cn All Rights Reserved