唐抉的个人博客

python学习笔记(四)

字数统计: 2.9k阅读时长: 13 min
2022/10/10

切片(Slice)

具体形式:L[0:3],其中L为list名称,0:3代表list的取值范围,与matlab中的数组取值类似。list、tuple、字符串可以用切片操作。

list切片

下面以一个list为例来说明切片的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
L=['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
print(L[0:3])#取前3个元素
print(L[:3])#第一个索引是0可省略
print(L[-2:])#取后2个元素
print(L[-2:-1])#取倒数第2的元素
print(L[0:4:2])#前4个数,每两个取一个
print(L[::2])#所有数,每两个取一个
print(L[:])#复制一个list
#运行结果如下:
['Michael', 'Sarah', 'Tracy']
['Michael', 'Sarah', 'Tracy']
['Bob', 'Jack']
['Bob']
['Michael', 'Tracy']
['Michael', 'Tracy', 'Jack']
['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']

tuple切片

由于tuple也是一种list,因此tuple也可以用切片操作,其操作结果仍是tuple:

1
2
3
4
L=(0,1,2,3,4)
print(L[:3])
#运行结果如下:
(0, 1, 2)

字符串切片

字符串也可以看成是一种list,因此,字符串也可以进行切片操作。

1
2
3
4
L='ZHANGSAN'
print(L[:3])
#运行结果如下:
ZHA

练习题

利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# -*- coding: utf-8 -*-
def trim(s):
n=0
m=len(s)
for i in range(len(s)):
if s[i]==' ':
n=n+1
else:
break
for j in range(len(s)):
if s[m-1]==' ':
m=m-1
else:
break
return s[n:m]
# 测试:
if trim('hello ') != 'hello':
print('测试失败!')
elif trim(' hello') != 'hello':
print('测试失败!')
elif trim(' hello ') != 'hello':
print('测试失败!')
elif trim(' hello world ') != 'hello world':
print('测试失败!')
elif trim('') != '':
print('测试失败!')
elif trim(' ') != '':
print('测试失败!')
else:
print('测试成功!')
#运行结果如下:
测试成功!

迭代

通过for循环来遍历list或tuple称为迭代。只要是可迭代对象,无论有无下标,都可以迭代。

迭代dict

默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values()语句,如果要同时迭代key和value,可以用for k,v in d.items()语句。由于dict的存储不是按照list的方式顺序排列,因此迭代出的结果顺序很可能不一样。

1
2
3
4
5
6
7
d={'a':1,'b':2,'c':3}
for key in d:
print(key)
#运行结果如下:
a
b
c

迭代字符串

字符串也是可迭代对象,也可以作用于for循环。

1
2
3
4
5
6
7
d='abc'
for key in d:
print(key)
#运行结果如下:
a
b
c

对list实现下标循环

通过enumerate函数把list变成索引-元素对,便可以在for循环中同时迭代索引和元素本身:

1
2
3
4
5
6
for i,value in enumerate(['A','B','C']):
print(i,value)
#运行结果如下:
0 A
1 B
2 C

练习题

请使用迭代查找一个list中最小和最大值,并返回一个tuple。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# -*- coding: utf-8 -*-
def findMinAndMax(L):
minl=999
maxl=0
if L==[]:
return (None, None)
for i in L:
if(minl>int(i)):
minl=i
if(maxl<int(i)):
maxl=i
return (minl, maxl)
# 测试
if findMinAndMax([]) != (None, None):
print('测试失败!1')
elif findMinAndMax([7]) != (7, 7):
print('测试失败!')
elif findMinAndMax([7, 1]) != (1, 7):
print('测试失败!')
elif findMinAndMax([7, 1, 3, 9, 5]) != (1, 9):
print('测试失败!')
else:
print('测试成功!')
#运行结果如下:
测试成功!

列表生成式

使用列表生成式,可以通过一个list快速生成另一个list。

如要生成list[1,2,3,4,5,6,7,8,9]可用list(range(1,10))生成。

若要生成[1x2,2x2,3x3,...,10x10]可用[x*x for x in range(1,11)]生成。

写列表生成式时,要把生成的元素放到前面,后面再跟for循环,for循环后可以加上if判断,也可以使用两层循环:

1
2
3
4
5
6
7
L=[x*x for x in range(1,11) if x%2==0]
print(L)
T=[m+n for m in 'ABC' for n in 'XYZ']
print(T)
#运行结果如下:
[4, 16, 36, 64, 100]
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

for循环可以同时使用两个或多个变量,如dict的items可以同时迭代key和value:

1
2
3
4
5
6
7
d={'x':1,'y':2,'z':3}
for k,v in d.items():
print(k,'=',v)
#运行结果如下:
x = 1
y = 2
z = 3

因此列表生成式也可以使用两个变量来生产list:

1
2
3
4
5
d={'x':'1','y':'2','z':'3'}
L=[k+'='+v for k,v in d.items()]
print(L)
#运行结果如下:
['x=1', 'y=2', 'z=3']

注意:这里的value只能为str类型,由于非字符串类型没有lower()方法,所以列表生成式会报错。可以使用isinstance函数来判断一个变量a是不是字符串,具体形式为isinstance(a,str)

if…else

使用列表生成式时,不能在最后的if加上else。这是因为跟在for后面的if是一个筛选条件,不能带else。而把if写在for前面必须加else,否则会报错。这是因为for前面的部分是一个表达式,其必须要计算出一个结果。

练习题

请修改列表生成式,通过添加if语句保证列表生成式能正确地执行。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
# -*- coding: utf-8 -*-
L1 = ['Hello', 'World', 18, 'Apple', None]
L2 = [k.lower() for k in L1 if isinstance(k,str)==True]
# 测试:
print(L2)
if L2 == ['hello', 'world', 'apple']:
print('测试通过!')
else:
print('测试失败!')
#运行结果如下:
['hello', 'world', 'apple']
测试通过!

生成器

在循环过程中不断推算出后续元素,故不必创建完整list,从而节省大量空间的机制,称为生成器(generator)。

创建生成器:将列表生成式的[]改成()

1
2
3
4
5
6
7
L=[x*x for x in range(10)]
print(L)
g=(x*x for x in range(10))
print(g)
#运行结果如下:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x7ff38be35ac0>

打印生成器的元素

方法一:

通过next()函数单个打印生成器中的元素,具体形式如下:next(g)

方法二:

使用for循环打印,具体形式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
g = (x * x for x in range (10))
for i in g:
print(i)
#运行结果如下:
0
1
4
9
16
25
36
49
64
81

如果生成器推算的算法比较复杂,用类型列表生成式的for循环无法实现时,还可以用函数来实现。比如打印斐波拉契数列:

1
2
3
4
5
6
7
8
9
10
def fib(max):
n,a,b=0,0,1
while n<max:
yield b
a,b=b,a+b#相当于t=(b,a+b),t是一个tuple,a=t[0],b=t[1]
n=n+1
return 'done'
print(fib(6))
#运行结果如下:
<generator object fib at 0x7f99e1f3dac0>

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator函数,调用一个generator函数将返回一个generator。变成generator的函数在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

例如,定义一个generator函数,依次返回数字1,3,5:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
o=odd()
next(o)
next(o)
next(o)
#运行结果如下:
step 1
step 2
step 3

而每次调用next(odd())时,每次都会返回1.这是由于odd()会创建一个新的generator对象,每次调用next(odd())就创建一个完全独立的generator。

在斐波那契数列的例子中,在循环里不断调用yield,就会不断中断程序,此时需要给循环设置一个条件来退出循环,不然就会产生一个无限的数列,

把函数改成generator函数后,基本上不会用next()来获取下一个返回值,而是直接用for循环来迭代:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def fib(max):
n,a,b=0,0,1
while n<max:
yield b
a,b=b,a+b#相当于t=(b,a+b),t是一个tuple,a=t[0],b=t[1]
n=n+1
return 'done'
for n in fib(6):
print(n)
#运行结果如下:
1
1
2
3
5
8

用for循环调用generator时,是拿不到generator的return语句的返回值,若想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def fib(max):
n,a,b=0,0,1
while n<max:
yield b
a,b=b,a+b#相当于t=(b,a+b),t是一个tuple,a=t[0],b=t[1]
n=n+1
return 'done'
g=fib(6)
while True:
try:
x=next(g)
print('g:',x)
except StopIteration as e:
print('Generator return value:',e.value)
break
#运行结果如下:
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done

练习题

杨辉三角定义如下:

1
2
3
4
5
6
7
8
9
10
11
          1
/ \
1 1
/ \ / \
1 2 1
/ \ / \ / \
1 3 3 1
/ \ / \ / \ / \
1 4 6 4 1
/ \ / \ / \ / \ / \
1 5 10 10 5 1

把每一行看做一个list,试写一个generator,不断输出下一行的list。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# -*- coding: utf-8 -*-

def triangles():
L=[1]
while True:
yield L
L=[1]+[L[n]+L[n-1] for n in range(1,len(L))]+[1]


# 期待输出:
# [1]
# [1, 1]
# [1, 2, 1]
# [1, 3, 3, 1]
# [1, 4, 6, 4, 1]
# [1, 5, 10, 10, 5, 1]
# [1, 6, 15, 20, 15, 6, 1]
# [1, 7, 21, 35, 35, 21, 7, 1]
# [1, 8, 28, 56, 70, 56, 28, 8, 1]
# [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
n = 0
results = []
for t in triangles():
results.append(t)
n = n + 1
if n == 10:
break

for t in results:
print(t)

if results == [
[1],
[1, 1],
[1, 2, 1],
[1, 3, 3, 1],
[1, 4, 6, 4, 1],
[1, 5, 10, 10, 5, 1],
[1, 6, 15, 20, 15, 6, 1],
[1, 7, 21, 35, 35, 21, 7, 1],
[1, 8, 28, 56, 70, 56, 28, 8, 1],
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
]:
print('测试通过!')
else:
print('测试失败!')
#运行结果如下:
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
测试通过!

迭代器

可以直接作用于for循环的对象统称为可迭代对象Iterable

判断一个对象是可迭代对象

可通过collections.abc模块的Iterable类型判断。

1
2
3
4
5
6
7
8
9
10
from collections.abc import Iterable
print(isinstance('abc',Iterable))#字符串是否可迭代
print(isinstance([1,2.3],Iterable))#list是否可迭代
print(isinstance(([1,2,3]),Iterable))#set是否可迭代
print(isinstance(123,Iterable))#整数是否可迭代
#运行结果如下:
True
True
True
False

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。这是因为Iterator的对象表示的是一个 数据流,可以把这个数据流看作是一个未知长度的有序序列,Iterator甚至可以表示一个无限大的数据流,例如全体自然数。

把list、dict、str从Iterable变成Iterator

可以使用iter()函数把list、dict、str从Iterable变成Iterator,其表现形式为:isinstance(iter([]),Iterator),其中,[]可替换为dict、str的形式。

小结

可作用于for循环的对象都是Iterable类型。

可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列。

list、dict、str虽然是Iterable,却不是Iterator。但可以使用iter()函数把list、dict、str从Iterable变成Iterator

CATALOG
  1. 1. 切片(Slice)
    1. 1.1. list切片
    2. 1.2. tuple切片
    3. 1.3. 字符串切片
    4. 1.4. 练习题
  2. 2. 迭代
    1. 2.1. 迭代dict
    2. 2.2. 迭代字符串
    3. 2.3. 对list实现下标循环
    4. 2.4. 练习题
  3. 3. 列表生成式
    1. 3.1. if…else
    2. 3.2. 练习题
  4. 4. 生成器
    1. 4.1. 打印生成器的元素
    2. 4.2. 练习题
  5. 5. 迭代器
    1. 5.1. 判断一个对象是可迭代对象
    2. 5.2. 小结