定义
目前学习到的数据结构:
- 列表
- 元组
- 字符串
- bytes
- bytearray
共同特点:
都是顺序存储,顺序访问的,都是可迭代对象,都可以通过索引访问
这样一类的结构称为:线性结构
线性结构的特点:
- 可迭代
- 可以用len方法获取长度
- 可以使用下标操作符通过索引访问
- 可以切片
例子如下:
for i in [1,2,3]:
print(i)
1
2
3
for i in 'i smart':
print(i)
i
s
m
a
r
t
enumerate
>>> enumerate((1,2,3))
<enumerate object at 0x000002170E0E0368>
#这里返回了一个可迭代对象
看看可迭代对象是什么:
>>> list(enumerate([1,2,3]))
[(0, 1), (1, 2), (2, 3)]
在这里用代码实现一个enumerate()函数:
#方式一,用yield封装:
def new_enumerate(iterator):
i = 0
for v in iterator:
yield i,v
i += 1
#方式二,便于理解:
def new_enumerate1(iterator):
ret = []
i = 0
for v in iterator:
ret.append((i,v))
i += 1
return ret
什么时候用到enumerate:同时获取索引和value的时候需要用这个函数。
例子:如果有一个list,这个list里是一个个的用户对象,而你在逻辑里还需要对他们的索引作计算:
>>> users = ['punch', 'xu', 'kidult', 'justin']
>>> for i,user in enumerate(users):
... print(i,':', user)
...
0 : punch
1 : xu
2 : kidult
3 : justin
迭代器
关于range()函数,用来获取一段范围内的数字,可能是连续的,可能不是连续的。
range(1,10,2),三个参数分别代表:
- 第一个参数,start:什么位置开始
- 第二个参数,end:什么位置结束
- 第三个参数,step:步长,每多少个值向下取一个
>>> list(range(1,10,3))
[1, 4, 7]
next函数是用来迭代可迭代对象的。next函数需要一个迭代器,而iter方法可以转化可迭代对象为迭代器。next不能直接迭代可迭代对象,list是一个可迭代对象,需要iter函数将可迭代话对象转换成迭代器。
>>> it = iter(list((1,2,3)))
>>> it
<list_iterator object at 0x000002170E0E3248>
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
#当next将迭代器的元素都迭代过一遍之后,再迭代就会抛出StopIteration异常
可迭代对象可以通过iter函数转换为迭代器,之后迭代器便可用next函数迭代
将list转化为迭代器这种方式,方便我们来获取数据,降低性能消耗。
切片操作
>>> lst = list(range(10))
>>> lst[3]
3
这个操作是通过索引获取列表的具体某一个元素
这个不是切片,切片是选择某一段:
>>> lst[3:7]
[3, 4, 5, 6]
lst是从0开始的连续整数,而索引也是从0开始的,因此索引为3的元素是对应整个列表从左往右的第4个元素。
而索引为7的元素,这里则规定,切片操作是左闭右开的取值范围。从3开始,再7前面一个结束。
即:lst[start:stop],可以访问lst从start开始到stop-1结束,不包含stop,并且原地不修改,有返回值。
#当start为0时可以省略:
>>> lst[:4]
[0, 1, 2, 3]
#当想获取最后一个值时可以省略stop参数:
>>> lst[7:]
[7, 8, 9]
#'lst[:]',等效于copy方法
>>> l2 = lst[:]
>>> l2
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> lst
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> lst[0] = 'a'
>>> lst
['a', 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l2
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#stop超出索引范围
>>> lst[:1000]
['a', 1, 2, 3, 4, 5, 6, 7, 8, 9]
#start超出索引范围
>>> lst[-100:]
['a', 1, 2, 3, 4, 5, 6, 7, 8, 9]
#start和stop都超出索引范围
>>> lst[-100:100]
['a', 1, 2, 3, 4, 5, 6, 7, 8, 9]
- start超出索引范围时,start=0
- stop超出索引范围时,stop=-1
#当start >= stop时,返回空列表
>>> lst[4:3]
[]
#负数索引,实际上等于len(lst)+index,
>>> lst[3:-3]
[3, 4, 5, 6]
用代码实现一遍:
def _slice(lst,start=0,stop=0):
#判断start和stop小于0时做什么
if start < 0:
start = len(lst) + start
if stop <= 0:
start = len(lst) +stop
#这里时判断越界行为
if stop <= start:
return []
if stop > len(lst):
stop = len(lst)
#存储切片后的结果
ret = []
#这里把元素索引和start、end对应起来
for i,v in enumerate(lst):
if i >= start and i < stop:
ret.append(v)
return ret
lst[start:stop:step],step参数表示一次增加多少
>>> lst[3:9:2]
[3, 5, 7]
>>> lst[9:3:-2]
[9, 7, 5]
>>> lst[::-2]
[9, 7, 5, 3, 1]
#下面为小技巧,可直接将列表倒序
>>> lst[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 'a']
实现带step的方法:
def _slice(lst, start=0, stop=0, step=1):
#存储切片后的结果
ret = []
current = start
if step > 0:
while current < stop:
try:
ret.append(lst[current])
except IndexError:
pass
current += step
if step < 0:
while current > stop:
try:
ret.append(lst[current])
except IndexError:
pass
current += step
return ret
小结
感觉这一章的知识还是非常实用的。
enumerate这个方法在列表循环的时候也是用的非常多,一次循环获取索引和元素,能够快速实现业务逻辑。
迭代器也是十分重要。用来做懒惰求值,提升代码性能。