参考教程:廖雪峰官网https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
Python高级特性
一、切片
如果要取出一个列表或元组的部分元素,可以通过直接下标方法:
lista=['apple','banana','cherry'] lista[0] lista[1] lista[2]
但如果要取再多个,或者前面(后面)多少个,或中间多少个,直接访问的方法就很不方便了。
Python提供了切片(Slice)操作符来实现这种功能,通过[m:n]的方式提取从第m个(含)到第n个(不含)范围内元素。
numbers=list(range(20)) #提取前面5个元素 print(numbers[:5]) #提取最后3个元素 print(numbers[-3:]) #提取从第3个元素开始的5个元素 print(numbers[2:7]) #还可以设置间隔幅度 #提取奇数,通过第二个冒号后设置幅度 print(numbers[1::2]) #直接复制原列表 lista=numbers[:] print(lista)
这种操作对于字符串和元组一样有效:
print('123 abc XYZ 890'[3:10])
练习题:
#利用切片操作,实现去掉字符串首尾空格的功能 def trim(s): l=len(s) #如果是空字符串 if l==0: return '' else: counter=0 for x in s: if x==' ': counter+=1 else: break #字符串全是空格的情况 if counter==l: return '' else: m=0 n=-1 for a in s: if a==' ': m+=1 else: break while s[n]==' ': n=n-1 return s[m:(l+n+1)] # 测试: 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('测试成功!')
二、迭代
如果给定一个可迭代对象,Python中可通过for...in来进行遍历循环,如字符串、列表、元组、字典这些都是可迭代对象。
#字符串迭代 for ch in 'ABC': print ch lista=list(range(1,101)) sum=0 #列表迭代 for i in lista: sum+=i print('sum=',sum) d = {'a': 1, 'b': 2, 'c': 3} #字典的键迭代 for key in d: print (key) #字典的值迭代: for value in d.values(): print (value) #键值同时迭代 for k,v in d.items() print(k,':',v)
Python中提供了collections模块中的iterable类型判断:
>>> from collections import Iterable >>> isinstance('abc',Iterable) True >>> isinstance([1,10,100],Iterable) True >>> isinstance(False,Iterable) False >>> isinstance(18,Iterable) False
Python中提供了enumerate函数,可以把一个列表变成索引-元素对,这样就可以在迭代索引和元素本身:
>>> for i,value in enumerate(['x','y','z']): print (i,value) 0 x 1 y 2 z
迭代两个变量的情况:
>>> for x, y in [(1, 1), (2, 4), (3, 9)]: ... print(x, y) ... 1 1 2 4 3 9
练习:
# -*- coding: utf-8 -*- #请使用迭代查找一个list中最小和最大值,并返回一个tuple: def findMinAndMax(L): if not L: return (None,None) else: max=L[0] min=L[0] for i in L: if max<i: max=i if min>i: min=i return (min,max) # 测试 if findMinAndMax([]) != (None, None): print('测试失败!') 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('测试成功!')
三、列表生成式
列表生成式是Python中内置可以用来生成列表的方法。
#生成0~49的整数列表 list(x for x in range(0,50)) #同上更简单的写法 list(range(0,50)) #奇偶数的列表生成 list(x for x in range(0,20) if x%2==0) list(x for x in range(0,20) if x%2==1) #生成1~9对应整数的平方值列表 list(x*x for x in range(1,10)) #两个变量两次迭代生成乘法算式 list(str(x)+'*'+str(y)+'='+str(x*y) for x in range(1,10) for y in range(1,10)) #迭代字典的列表生成 d={'A':'100,'B':200,'C':300} list(m+'='+str(n) for m,n in d.items())
#判断一个列表中元素是否为字符串 #重新生成只包含其中字符串的列表,并且转为小写 # -*- coding: utf-8 -*- L1 = ['Hello', 'World', 18, 'Apple', None] L2 = [x for x in L1 if isinstance(x,str)] print(L2) if L2 == ['hello','world','apple']: print('测试通过!') else: print('测试失败!')
四、生成器
受内存限制,列表的容量总是有限的;同时某些情况下,一个包含大量元素的列表我们只需要访问前面若干个元素,这样的话列表的其他元素就浪费了大量内存资源。Python中提供了一种在循环的过程中不断推算后续元素的方法,这样就不必创建完整的列表,这种方式称为生成器(generator)。
举例说明上述说法,比如需要生成一个2,4,8,16,32...,2^n的序列,这显然是一个无穷的序列,需要输出多少个元素完全依靠用户的需求。
>>> def fun2N(): n=1 while True: yield 2**n n=n+1 >>> x=fun2N() >>> next(x) 2 >>> next(x) 4 >>> next(x) 8 >>> next(x) 16 >>> next(x) 32 >>> next(x) 64 >>> next(x) 128
生成器有两种创建的方法:
第一种类似于列表生成式,只是把[]改成():
#生成列表L L=[x*x for x in range(10)] #创建类似的生成器gL gL=(x*x for x in range(10))
如上述创建好生成器后,可以通过next()方法逐个获得生成器的返回值
#这里看出创建的gL是一个生成器对象 >>> gL <generator object <genexpr> at 0x0000000002BFA518> #通过next()逐个获取返回值 >>> next(gL) 0 >>> next(gL) 1 >>> next(gL) 4 >>> next(gL) 9 >>> next(gL) 16 >>> next(gL) 25 >>> next(gL) 36 >>> next(gL) 49 >>> next(gL) 64 >>> next(gL) 81 #循环结束,抛出StopIteration错误 >>> next(gL) Traceback (most recent call last): File "<pyshell#30>", line 1, in <module> next(gL) StopIteration
但上面的next()方法明显太麻烦了,因为generator也是可迭代对象,所以可以通过for/in循环去访问元素。先测试一下可迭代性:
>>> from collections import Iterable >>> isinstance(gL,Iterable) True
>>> gL=(x*x for x in range(5)) >>> for i in gL: print (i) 0 1 4 9 16
创建生成器的第二种方法是函数的方式,比如对应上述生成器的函数生成方法如下:
def gL(): for i in range(5): yield i**2
与函数的定义不同,生成器的函数创建方式中返回是通过yield关键字来实现;在执行过程中不断执行、中断、执行、中断直至没有元素了结束(抛出StopIteration)。每一次生成的就是yield语句的返回值,下一次生成再从上一次yield的下一句开始执行直至本次yield返回为止。
生成器的函数创建方法中也可以包括return语句,比如在上述gL中,我们可以在所有元素生成结束后给它一个return的返回值:
def gL(): for i in range(5): yield i**2 return 'DONE'
斐波拉契数列是一个无限的集合,无法用列表保存,但却可以通过生成器的方式表示:
def fibGen(): a,b=1,1 while True: yield a a,b=b,a+b x=input("输入1结束输出,其他继续输出斐波拉契数列:") f1=fibGen() while (x!=str(1)): print(next(f1)) x=input()
因为生成器的可迭代性,所以在给定的条件下,我们可以利用for/in循环方式输出一定条件下的斐波拉契数列:
#输出小于2000的数列值 for i in fibGen(): if (i<2000): print (i) else: break
上面的方法也可以给出参数:
def fibGen1(n): a,b=1,1 counter=0 while (counter<n+1): yield a a,b=b,a+b counter=counter+1 for x in fibGen1(16): print(x)
练习:
''' 杨辉三角定义如下: 1 / 1 1 / / 1 2 1 / / / 1 3 3 1 / / / / 1 4 6 4 1 / / / / / 1 5 10 10 5 1 把每一行看做一个list,试写一个generator,不断输出下一行的list: ''' #思路:把上一个列表的最后补0后,当前列表的每个元素都可以通过上列表的俩元素之和得出 def yhsj(): L=[1] while True: yield L L.append(0) L=[L[i]+L[i-1] for i in range(len(L))] for xL in yhsj(): print(xL) x=input("输入1停止输出") if (x==str(1)): break
五、迭代器
前面说到可以通过for循环的数据类型包括两类,一类是集合类如list,tuple,dict,set,str等;另外一类就是生成器generator;这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以使用isinstance()方法进行判断:
>>> isinstance('abc',Iterable) True >>> isinstance([x for x in range(9)],Iterable) True >>> isinstance((x for x in range(9)),Iterable) True >>> isinstance([],Iterable) True >>> isinstance({},Iterable) True
而生成器除了可以同for循环来调用外还可以通过next()函数不断调用,直到结束,对于这种可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。一样可以通过isinstance()来判断:
>>> from collections import Iterator >>> isinstance('ABC',Iterator) False >>> isinstance([],Iterator) False >>> isinstance({},Iterator) False >>> isinstance((x for x in range(9)),Iterator) True >>> isinstance([x for x in range(9)],Iterator) False
可以看出listdictstr都不是迭代器,可以通过iter()函数将他们转换成迭代器:
>>> isinstance(iter('ABC'),Iterator) True >>> isinstance(iter([1,2,3]),Iterator) True
Python的Iterator对象表示的是一个数据流,可以被next()函数不断调用直到抛出StopIteration错误。我们不能提前知道这个输出序列的长度,只有需要返回下一个数据时候才会被计算出来。