文章目录
- 一.切片
- 二.迭代
- 三.列表生成式
- 四.生成器
- 五.迭代器
一.切片
取一个list
或tuple
的部分元素是非常常见的操作。比如,一个list如下:
L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
取前3个元素,应该怎么做?
-
笨办法
[L[0], L[1], L[2]]
- 输出结果
['Michael', 'Sarah', 'Tracy']
取前N个元素,也就是索引为0-(N-1)
的元素,可以用循环:
r = []
n = 3
for i in range(n):r.append(L[i])print(r)
-
输出结果
['Michael', 'Sarah', 'Tracy']
这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符
,能大大简化这种操作。
-
取前3个元素,用一行代码就可以完成切片:
print( L[0:3]) #打印结果: ['Michael', 'Sarah', 'Tracy']
-
L[0:3]
表示,从索引0
开始取,直到索引3
为止,但不包括索引3。即索引0,1,2
,正好是3个元素。- 如果第一个索引是0,还可以省略:
print( L[:3])
类似的,既然Python支持L[-1]取倒数第一个元素
,那么它同样支持倒数切片
,试试:
- 倒数第一个元素的索引是-1。
print(L[-2:]) #执行结果 ['Bob', 'Jack']print( L[-2:-1]) #执行结果 ['Bob']
演示1-100的切分
# 先创建一个0-99的数列:
L = list(range(100))# 前10个数:
print(L[:10])
#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]# 后10个数:
print(L[-10:])
#[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]# 前11-20个数:
print(L[10:20])
#[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]# 前10个数,每两个取一个:
print(L[:10:2])
#[0, 2, 4, 6, 8]# 所有数,每5个取一个:
print(L[::5])
#[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]# 甚至什么都不写,只写[:]就可以原样复制一个list:
L2 = L[:]
print(L2)
#[0, 1, 2, 3,省略中间部分, 99]
tuple和字符串
- tuple也是一种
list
,唯一区别是tuple不可变
。因此,tuple也可以用切片操作,只是操作的结果仍是tuple:
(0, 1, 2, 3, 4, 5)[:3]
#前3
#(0, 1, 2)
- 字符串’xxx’也可以看成是一种
list
,每个元素就是一个字符
。因此,字符串也可以用切片操作,只是操作结果仍是字符串:
#前3
'ABCDEFG'[:3]
#'ABC'
# 所有数,每2个取一个:
'ABCDEFG'[::2]
#'ACEG'
二.迭代
给一个list或tuple
,通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)
。
- 在Python中,迭代是通过
for ... in
来完成 - 只要是可迭代对象,无论有无下标,都可以迭代
比如dict
就可以迭代:
d = {'a': 1, 'b': 2, 'c': 3}
for key in d:print(key)#执行结果
#a
#c
#b
- 默认情况下,
dict迭代的是key
。如果要迭代value,可以用for value in d.values()
,如果要同时迭代key和value
,可以用for k, v in d.items()
。
字符串
也是可迭代对象
for ch in 'ABC':print(ch)
#执行结果
#A
#B
#C
如何判断一个对象是可迭代对象呢?
- 通过
collections.abc模块
的Iterable类型
判断:
from collections.abc import Iterableisinstance('abc', Iterable) # str是否可迭代
#True
isinstance([1,2,3], Iterable) # list是否可迭代
#Trueisinstance(123, Iterable) # 整数是否可迭代
#False
如果要对list实现类似Java那样的下标循环怎么办?
- Python内置的
enumerate函数
可以把一个list变成索引-元素对
,这样就可以在for循环中同时迭代索引和元素本身:
for i, value in enumerate(['A', 'B', 'C']):print(i, value)
#执行结果
#0 A
#1 B
#2 C
三.列表生成式
列表生成式即Python内置的非常简单却强大的可以用来创建list的生成式
。
-
要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用
list(range(1, 11)):
list(range(1, 11)) #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-
但如果要生成
[1x1, 2x2, 3x3, ..., 10x10]
怎么做?方法一是循环:L = [] for x in range(1, 11):L.append(x * x)print(L) #[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
-
但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的list:
[x * x for x in range(1, 11)] #[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
-
for循环后面还可以
加if判断进行过滤
,这样我们就可以筛选出仅偶数的平方:x * x for x in range(1, 11) if x % 2 == 0] #[4, 16, 36, 64, 100]
-
for前面加if-else
- for前面的部分是一个
表达式
,它必须根据x计算出一个结果
。- 因此达式:
x if x % 2 == 0,
它无法根据x计算出结果,因为缺少else,必须加上else
:
- 因此达式:
[x if x % 2 == 0 else -x for x in range(1, 11)] #[-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]
- 列表生成式中,for前面的
if ... else是表达式
,而for后面的if是过滤条件,不能带else
。
- for前面的部分是一个
四.生成器
在Python中,这种一边循环一边计算的机制,称为生成器:generator。
-
创建generator第一种方法很简单,
只要把一个列表生成式的[]改成()
,就创建了一个generator:L = [x * x for x in range(10)] print(L) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]g = (x * x for x in range(10)) print(g) # <generator object <genexpr> at 0x00000219AF47CDD0>
L和g
的区别仅在于最外层的[]和()
,L是一个list
,而g是一个generator。
-
如何打印出generator的每一个元素呢?
- 如果要一个一个打印出来,可以通过
next()
函数获得generator的下一个返回值
:
g = ( x for x in range(10)) for n in g:print(n)
- 如果要一个一个打印出来,可以通过
-
如果一个函数中包含
yield关键字
,那这个函数就是generator函数,调用一个generator函数将返回一个generator:def odd():print('step 1')yield 1print('step 2')yield(3)print('step 3')yield(5)
-
调用该generator函数时,
首先要生成一个generator对象
,然后用next()函数
不断获得下一个返回值:o = odd() next(o) next(o) next(o)
-
generator的函数,在每次调用
next()
的时候执行,遇到yield语句返回
,再次执行时从上次返回的yield语句处继续执行
。
-
五.迭代器
可以直接作用于for循环的数据类型有以下几种:
- 集合数据类型,如
list、tuple、dict、set、str
等; - generator,包括生成器和带yield的
generator function
。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable
。
-
可以使用
isinstance()
判断一个对象是否是Iterable对象
:from collections.abc import Iterableisinstance([], Iterable) #Trueisinstance({}, Iterable) #Trueisinstance('abc', Iterable) #Trueisinstance((x for x in range(10)), Iterable) #Trueisinstance(100, Iterable) #False
生成器不但可以作用于for循环,还可以被next()函数
不断调用并返回下一个值
,直到最后抛出StopIteration错误
表示无法继续返回下一个值了。
-
可以被
next()函数
调用并不断返回下一个值的对象称为迭代器:Iterator
。-
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
- 把list、dict、str等Iterable变成Iterator可以使用
iter()函数
:
isinstance(iter([]), Iterator) #True isinstance(iter('abc'), Iterator) #True
- 把list、dict、str等Iterable变成Iterator可以使用
-
小结
-
凡是可作用于
for循环
的对象都是Iterable
类型; -
凡是可作用于
next()函数
的对象都是Iterator类型
,它们表示一个惰性计算的序列; -
集合数据类型如
list、dict、str
等是Iterable但不是Iterator,不过可以通过iter()函数
获得一个Iterator对象。