切片
对这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符,能大大简化这种操作。
作业
#尝试区分这两块代码的区别def trim(s):while s[0] == " ":s=s[1:]while s[-1] == " ":s=s[:-1]return s#代码2def trim(s):while s[:1] == ' ':s=s[1:]while s[-1:] == ' ':s=s[:-1]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('测试成功!')
迭代
如果给定一个list或者tuple ,我们可以通过 for in来遍历这个list或者tuple,这种遍历我们称之为迭代;
d=[1,2,3,4,5]for x in d:print(x)
#一般迭代dice只会输出keyd = {'a': 1, 'b': 2, 'c': 3}for x in d:print(x)#但是也可以输出 value;for x in d.value():print(x)#如果同时迭代两个也可以for x,k in d.items():print(f"{x},{k}")
d = "ABCDFEFG"for x in d:print(f"{x},")
所以我们不太关系本身能否迭代,但是如果我们需要监测该对象能否迭代这么办呢?使用模块
from collections.abc import Iterabled = {"a":1,"b":2,"c":3}print(isinstance(d,Iterable))isinstance(123, Iterable)
作业
请使用迭代查找一个list中最小和最大值,并返回一个tuple:
def findMinAndMax(L):if len(L)==0:return (None, None)else:# 初始化最大最小值min=L[0]max=L[0]for x in L:if max < x:max = xif min > x:min = xreturn (min,max)# 测试if findMinAndMax([]) != (None, None):print('测试失败!1')elif findMinAndMax([7]) != (7, 7):print('测试失败!2')elif findMinAndMax([7, 1]) != (1, 7):print('测试失败!3')elif findMinAndMax([7, 1, 3, 9, 5]) != (1, 9):print('测试失败!4')else:print('测试成功!')
列表生成式
用更加简略的方式表达, for 循环 ,中间可以加 if 判断
#尝试运行这些代码以理解L = [x*x for x in range(1,11)]print(L)#加判断L = [x*x for x in range(1,11) if x % 5 == 0]print(L)#另一种方式加判断#筛选出字符串并且转换成小写L = ['Hello', 'World', 18, 'Apple', None]L2 =[s.lower() for s in L if isinstance(s,str)]print(L2)if L2 == ['hello', 'world', 'apple']:print('测试通过!')else:print('测试失败!')#else怎么加?else必须加到前面,使得成为一个完整的表达式#为什么不能加在后面?因为加在后面的 if 是一个筛选条件,不能加else#为什么 if 加在前面也不行,因为for 前面必须是一个完整的表达式L = [x if x % 2 == 0 else -x for x in range(1, 11)]print(L)
生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
可以把generator 单单看作一个算法,他不会输出结果,只是一个计算的公式;
#generator也是一个可迭代对象L = (x for x in range(1,101) if x%10 ==0) #和列表生成式的区别是使用“()”包裹a=[]for x in L:a.append(x)print(a)
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator函数
def fib(max):n, a, b = 0, 0, 1while n < max:print(b)a, b = b, a + bn = n + 1return 'done'#把 print 输出改为 yield 就变成了一个算法;def fib(max):n, a, b = 0, 0, 1while n < max:yield ba, b = b, a + bn = n + 1return 'done'
要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。
请注意区分普通函数和generator函数,普通函数调用直接返回结果:
>>> r = abs(6)>>> r6
generator函数的调用实际返回一个generator对象:
>>> g = fib(6)>>> g<generator object fib at 0x1022ef948>
迭代器
我们已经知道,可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function【生成器函数】。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
可以使用isinstance()判断一个对象是否是Iterable对象
>>> 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
但是
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
>>> from collections.abc import Iterator>>> isinstance((x for x in range(10)), Iterator)True>>> isinstance([], Iterator)False>>> isinstance({}, Iterator)False>>> isinstance('abc', Iterator)False
小结
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
详细参考
https://www.liaoxuefeng.com/wiki/1016959663602400/1017323698112640
