1. 切片
本小节的课后习题: 在不调用str的strip()方法情况下,实现一个trim()函数,去除字符串首尾的空格。
(自己写了半天,然后一看别人写的,非常简洁。要注意利用递归。)
def trim(s):
if len(s) != 0:
if s[0] == ' ':
return trim(s[1:])
elif s[-1] == ' ':
return trim(s[:-1])
else:
return s
else:
return s
# 测试:
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('测试成功!')
2. 迭代
# 除常规list/tuple外
# 可迭代dic
d = {'a': 1, 'b': 2, 'c': 3}
# (1)迭代键
for key in d:
# (2)迭代值
for value in d.values()
# (3) 迭代键值对
for k,v in d.items()
# 可迭代字符串
for ch in 'ABC':
# 判断是否可迭代
from collections import Iterable
isinstance('abc',Iterable)
isinstance(123,Iterable)
3. 列表生成式
L = []
for x in range(1,11):
L.append(x*x)
# (1)用列表生成式实现
[x*x for x in range(1,11)]
# (2)选取偶数乘积
[x*x for x in range(1,11) if x % 2 == 0]
# (3)使用两层循环,实现全排列
[m+n for m in 'ABC' for n in 'WXYZ']
# (4)也可以加上条件判断
L2 = [i.lower() for i in L1 if isinstance(i,str)]
# 测试:
print(L2)
if L2 == ['hello', 'world', 'apple']:
print('测试通过!')
else:
print('测试失败!')
4. 生成器
(1)generator
当我们创建一个包含100万个元素的列表时,会占用极大存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都被浪费了。
于是,我们希望列表元素可以按照某种算法推算出来,以便于在不创建完整 list 情况下,一边循环 一边计算 一边供使用。这样的机制,称为生成器:generator。
(理解为 生成器是返回迭代器的函数)
L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 生成器
g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
# 取元素
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
# 每次调用next(g),取 g 的下一个值,直到计算出最后一个元素,当没有更多元素时,抛出 StopIteration 错误
# 但这样调用next(g) 很麻烦,generator 也是可迭代的对象,用 for 循环迭代
L = (x*x for x in range(10))
for n in L:
print(n)
(2)yield
# 用函数生成斐波拉契数列(除第一个和第二个数外,任意一个数都可由前两个数相加得到:1, 1, 2, 3, 5, 8, 13, 21, 34, ...)
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
# 注意!
a, b = b, a + b
# 其实相当于,不通过显式写出临时变量t就可以赋值
# t 是 tuple
t = (b, a + b)
a = t[0]
b = t[1]
上述实例的逻辑非常类似 generator,只需要将 print 改为 yield,就是 generator
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
# 在用 for 循环调用 generator 时,如果想要拿到返回值,必须捕获 StopIteration 错误
g = fib(6)
while True:
try:
x = next(g)
print('g:',x)
except StopIteration as e:
print('Generator return value:', e.value)
break
本例总结:
- 函数是顺序执行,遇到return语句或者最后一行函数语句就返回
- 变成generator的函数,在每次调用 next() 的时候执行,遇到 yield 返回,再次执行时从上次返回的 yield 处继续执行
补充: 看到一个关于 yield 的小例子,很清晰
def fol():
print('strating...')
while True:
res = yield 4
print('res: ', res)
g = fol()
print(next(g))
print('*'*20)
print(next(g))
>>> strating...
>>> 4
>>> ********************
>>> res: None
>>> 4
5. 迭代器
可以被 next() 调用并不断返回下一个值的对象称为迭代器:Iterator
# 判断是否可迭代
from collections.abc import Iterable
isinstance([], Iterable)
>>> True
isinstance({}, Iterable)
>>> True
isinstance('abc', Iterable)
>>> True
isinstance((x for x in range(10)), Iterable)
>>> True
isinstance(100, Iterable)
>>> False
# 判断是否是迭代器对象
from collections.abc import Iterator
isinstance((x for x in range(10)), Iterator)
>>> True
isinstance([], Iterator)
>>> False
isinstance({}, Iterator)
>>> False
isinstance('abc', Iterator)
>>> False
本例总结:
- 生成器(generator)都是迭代器(iterator)对象
- list、dict、str虽然可迭代 Iterable,但却不是迭代器对象 Iterator。可以通过 iter() 函数,转换为迭代器对象
总结:
- 凡是可以用 for 循环的,都是可迭代的(Iterable)
- 凡是可以用 next() 的,都是迭代器(iterator)对象