Python基础笔记:高级特性:切片、迭代、列表生成式、生成器、迭代器
题记:
在python中,代码不是越多越好,而是越少越好。代码不是越复杂越好,而是越简单越好。
1行代码能实现的功能,绝不写5行代码。
请始终牢记:代码越少,开发效率越高。
切片
>>> L=list(range(11)) #生成数0~10 >>> L [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> L[:5] #输出0~4 [0, 1, 2, 3, 4] >>> L[-5:] #输出倒数第5个~最后 [6, 7, 8, 9, 10] >>> L[3:7] #输出3~6 [3, 4, 5, 6] >>> L[0:6:2] #在0~5,每隔2个取一个 [0, 2, 4] >>> L[::5] #在整个list L上,每隔5个取一个 [0, 5, 10]
编写程序:实现一个trim()函数,取出字符串首尾的空格
def trim(x): l=len(x) a=0 b=0 for i in range(l): if x[i]!=' ': a=i break if a==l-1: return else: for i in range(l): if x[l-i-1]!=' ': b=l-i break
def trim(x): #递归函数实现 if x[0]==' ': x=trim(x[1:]) if x[-1]==' ': x=trim(x[:-2]) return x >>> from hello import trim >>> trim('hello ') 'hello'
迭代(Iterate)
可以迭代的有str,list,tuple,dict ; 迭代是通过for...in来完成的
怎么判断一个对象是否是可迭代对象呢?
>>> from collections import Iterable >>> isinstance('abc',Iterable) True >>> isinstance([1,2,3],Iterable) True >>> isinstance(123,Iterable) False
一些迭代示例:
>>> d={'a':1,'b':2,'c':3} #对dict进行迭代 >>> for key in d: #迭代键值 ... print(key) ... a b c >>> for v in d.values(): ... print(v) ... 1 2 3 >>> for key,v in d.items(): #迭代list里元素 ... print(key,v) ... a 1 b 2 c 3 for ch in 'ABC': #对str迭代 ... print(ch) ... A B C >>> for i,value in enumerate(['A','B','C']): #把list变成索引-元素对 ... print(i,value) ... 0 A 1 B 2 C >>> for i in enumerate(['A','B','C']): ... print(i) ... (0, 'A') (1, 'B') (2, 'C') >>> L=[] >>> for i in enumerate(['A','B','C']): ... L.append(i) ... >>> L [(0, 'A'), (1, 'B'), (2, 'C')]
编程:使用迭代查找一个list中最小和最大值,并返回一个tuple
def find_mm(x): if len(x)==0: return (None,None) else: a=min(x) b=max(x) return (a,b) >>> from hello import find_mm >>> x=[7] >>> find_mm(x) (7, 7)
列表生成器
示例:
>>> [x*x for x in range(1,11)] #生成1*1 2*2 ... 10*10 的列表 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] >>> [x*x for x in range(1,11) if x%2==0] #仅筛选出偶数的平方 [4, 16, 36, 64, 100] >>> [m+n for m in 'ABC' for n in 'XYZ'] #生成连个串的全排列 ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] >>> d={'x':'1','y':'2','z':'3'} #把dict生成列表 >>> [k+v for k,v in d.items()] ['x1', 'y2', 'z3'] >>> [k+'='+v for k,v in d.items()] ['x=1', 'y=2', 'z=3'] C:\work>python #在C:\work 目录下打开python解释器 Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import os #导入os模块 >>> L=[d for d in os.listdir('.')] #os.listdir可以列出文件和目录 >>> ss=[s.upper() for s in L] #把list中所有的字符串变成大写 >>> ss ['HELLO.PY', '__PYCACHE__'] >>> ss=[s.lower() for s in L] #把list中所有的字符串变成小写 >>> ss ['hello.py', '__pycache__'] >>> >>> for i in ss: ... if i=='hello.py': ... print('Right here!') ... Right here!
内置函数 isinstance(x,str)、isinstance(x,int) 用来判断x是否是str型或int型
>>> x=5 >>> if isinstance(x,int)==True: ... print('yes!') ... yes! >>> x='fuck you!' >>> if isinstance(x,str)==True: ... print('yes!') ... yes!
上面判断一个数据是否可以迭代也是 isinstance() 这个函数(名);
练习:修改列表生成式,通过添加 if 语句保证列表生成式能正确地执行
L1=['Hello','World',18,'Apple',None]
>>> L1 = ['Hello', 'World', 18, 'Apple', None] >>> L2=[s.lower() for s in L1 if isinstance(s,str)==True] >>> L2 ['hello', 'world', 'apple']
生成器:一边循环一边计算的机制
迭代器:已经计算完毕,进行循环
生成器(generator)
要创建一个generator :只要把一个列表生成式的[ ] 改成 ( ) ,就创建了一个generator:
>>> g=(x*x for x in range(10)) >>> g <generator object <genexpr> at 0x000001E5405C7830>
可以用next() 函数一个一个打印出来generator 的下一个返回值;
>>> g=(x*x for x in range(10)) >>> g <generator object <genexpr> at 0x000001E5405C7830> >>> next(g) 0 >>> next(g) 1 >>> next(g) 4 >>> next(g) 9 ..... >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration #genereator 保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
当然,generator是可迭代的:
>>> isinstance(g,Iterable)
True
>>> for i in g: ... print(i) ... 16 25 36 49 64 81 >>> #generator g 好像有记忆一项,上次利用next函数输出到9,这次从16开始输出!
有输出斐波那契数列的函数:
def fib(max): n,a,b=0,0,1 while n<max: print(b) a,b=b,a+b n+=1 return 'done'
把这个函数换成generator 只需要把 print(b) 改为 yield b 就可以了。
def fib(max): n,a,b=0,0,1 while n<max: yield b a,b=b,a+b n+=1 return 'done' a = f() #创建生成器对象 for i in range(10): #斐波那契数列中前10个元素 print(a.__next__(), end=' ') 1 1 2 3 5 8 13 21 34 55
>>> from hello import fib >>> f=fib(5) >>> for i in f: ... print(i) ... 1 1 2 3 5 #如果是函数的话: >>> f=fib(6) 1 1 2 3 5 8
但是用for 循环调用generator 时,发现拿不到generator 的return 语句的返回值。如果想要拿到返回值,必须不过StopIteration 错误,返回值包含在StopIteration 的 value 中:
>>> from hello import fib >>> 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
编程:输出杨辉三角
def triangle(max): n,L=0,[1] for i in range(max): yield L s=[] if len(L)>=2: for j in range(len(L)-1): s.append(L[j]+L[j+1]) s.append(1) s.insert(0,1) L=s return 'done'
>>> t=triangle(10) >>> while True: ... try: ... x=next(t) ... print('t:',x) ... except StopIteration as e: ... print('Generator return value:',e.value) ... break ... t: [1] t: [1, 1] t: [1, 2, 1] t: [1, 3, 3, 1] t: [1, 4, 6, 4, 1] t: [1, 5, 10, 10, 5, 1] t: [1, 6, 15, 20, 15, 6, 1] t: [1, 7, 21, 35, 35, 21, 7, 1] t: [1, 8, 28, 56, 70, 56, 28, 8, 1] t: [1, 9, 36, 84, 126, 126, 84, 36, 9, 1] Generator return value: done
迭代器
直接作用于 for 循环的数据类型有:
1.集合数据类型,如list、tuple、dict、set、str等;
2.generator ,包括生成器和带yield 的generator function。
可以被next() 函数调用并不断返回下一个值的对象称为迭代器:Iterator
>>> from collections import Iterable >>> isinstance([], Iterable) #使用isinstance()#判断一个对象是否是Iterable对象 True >>> isinstance((x for x in range(10)), Iterator) #判断一个对象是否是Iterator对象 True
你可能会问,为什么list
、dict
、str
等数据类型不是Iterator
?
这是因为Python的Iterator
对象表示的是一个数据流,Iterator对象可以被next()
函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration
错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。