切片
对这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符,能大大简化这种操作。
作业
#尝试区分这两块代码的区别
def trim(s):
while s[0] == " ":
s=s[1:]
while s[-1] == " ":
s=s[:-1]
return s
#代码2
def 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只会输出key
d = {'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 Iterable
d = {"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 = x
if min > x:
min = x
return (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, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
#把 print 输出改为 yield 就变成了一个算法;
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。
请注意区分普通函数和generator函数,普通函数调用直接返回结果:
>>> r = abs(6)
>>> r
6
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