【十】迭代器、生成器、装饰器和标准库
一:迭代器
在python中,很多对象可以直接通过for语句来直接遍历,例如:list、string、dict等等,这些被称为可迭代对象
迭代器是一个可以I记住遍历的位置的对象。
在python中,支持迭代器协议的就是实现对象的iter()和next()方法。
- iter()方法返回迭代器本身
- next()方法返回容器的下一个元素
- 在结尾时引发stopiteration异常
迭代器有两个基本的方法:__iter__()和next()方法,一个用来获取迭代器对象,一个用来获取容器中的下一个元素
In [1]: l=[1,2,3,4,54] In [2]: it=iter(l) #通过iter()方法获得了list的迭代对象 In [3]: it Out[3]: <list_iterator at 0x7f4242c89e10> #通过next方法获取下一个元素 In [4]: next(it) Out[4]: 1 In [5]: next(it) Out[5]: 2 In [6]: next(it) Out[6]: 3 In [7]: next(it) Out[7]: 4 In [8]: next(it) Out[8]: 54 #当容器中没有可访问的元素后,抛出stopiteration异常 In [9]: next(it) --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-9-2cdb14c0d4d6> in <module>() ----> 1 next(it) StopIteration:
其实,当我们使用for语句的时候,for语句会自动通过iter()方法来获得迭代对象,并通过next()方法获取下一个元素
二:生成器
生成器是用来创建python序列的一个对象,使用它可以迭代庞大的序列,且不需要在内存中创建和储存整个序列
#range生成器 In [10]: sum(range(1,101)) Out[10]: 5050
每次迭代生成器,它都会记录上一次调用的位置,并且返回下一个值
生成器函数和普通函数类似,但是他的返回值使用yield语句声明,而不是return
生成器是为迭代器产生数据的。
In [14]: def my_range(first=0,last=10,step=1): ...: number=first ...: while number<last: ...: yield number ...: number+=step ...: #这是一个普通的函数 >>> my_range <function my_range at 0x1070c4e18> #返回的是一个生成器对象 In [15]: my_range() Out[15]: <generator object my_range at 0x7f4241b83fc0> #对这个生成器对象进行迭代 In [16]: ranger=my_range(1,5) In [17]: for i in ranger: ...: print(i) ...: 1 2 3 4 In [18]: print(ranger) <generator object my_range at 0x7f424291ea40> #在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行 next()方法时从当前位置继续运行。 In [19]: list(ranger) Out[19]: []#因为yield是记住位置的,ranger只里面的内容在for迭代已经全部取出来了,所以这里面为空 In [20]: ranger=my_range(1,5) #还没有进行迭代,所以数据都还存在 In [21]: list(ranger) Out[21]: [1, 2, 3, 4]
习题:使用生成器写一个斐波纳挈数列
In [24]: def shulie(): ...: num=int(input("请输入一个整数")) ...: f1=0 ...: f2=1 ...: if num<=0: ...: print("请输入一个正整数") ...: elif num==1: ...: print("斐波纳挈数列:%d"%f1) ...: else: ...: print("斐波纳挈:",end="") ...: for n in range(1,num-1): ...: f=f1+f2 ...: f1,f2=f2,f ...: print(f,end="") ...: In [25]: shulie() 请输入一个整数0 请输入一个正整数 In [26]: shulie() 请输入一个整数1 斐波纳挈数列:0 #输出前10项的斐波纳挈数列 In [29]: shulie() 请输入一个整数10 斐波纳挈:12358132134
三:装饰器
1.args和*kwargs
In [46]: def x(*args,**kwargs): ...: print(args) #输出参数的时候不需要加* ...: print(kwargs) ...: #从如下例子可以看出,*args就是一个列表,**kwargs就是一个字典 In [47]: x(1,2,3) (1, 2, 3) {} In [49]: x(1,2,3,one=1,two=2) (1, 2, 3) {'two': 2, 'one': 1} In [50]: x(one=1,two=2) () {'two': 2, 'one': 1}
2.闭包
In [51]: def foo(x,y): #x,y为自由变量 ...: def bar(): ...: a=4 ...: return x+y+a ...: return bar ...: In [52]: bar=foo(1,2) In [53]: bar Out[53]: <function __main__.foo.<locals>.bar> In [54]: bar() Out[54]: 7
3.作为参数的函数
函数document_it()定义了一个装饰器,需实现如下功能:
- 打印输出函数的名字和参数值
- 执行含有参数的函数
- 打印输出结果
- 返回修改后的函数
#装饰器 In [75]: def documenyt_it(func): ...: def new_func(*args,**kwargs): ...: print("func name",func.__name__) ...: print("args",args) ...: print("kwargs",kwargs) ...: result=func(*args,**kwargs) ...: print("result",result) ...: return result ...: return new_func ...: In [76]: def add(a,b): ...: return a+b ...: In [77]: add(3,5) Out[77]: 8 In [78]: test_add=documenyt_it(add) #人工对装饰器赋值 In [79]: test_add(3,5) func name add args (3, 5) kwargs {} result 8 Out[79]: 8
#自己设定装饰器
#coding=utf-8 def document_it(func): def new_func(*args,**kwargs): print('func name',func.__name__) print('args',args) print('keyword args',kwargs) result=func(*args,**kwargs) print('result',result) return result return new_func def square_it(func): def new_function(*args,**kwargs): result=func(*args,**kwargs) return result*result return new_function @square_it #装饰器 @document_it def add(a,b): return a+b #注意:打印结果:函数越靠近哪个装饰器就执行那个装饰器内的数据 print(add(3,5)) #add=add(sqare_it(document_it(add)))
打印结果:
C:\Python27\python.exe "D:/PyCharm Community Edition 5.0.3/代码/ex89.py" ('func name', 'add') ('args', (3, 5)) ('keyword args', {}) ('result', 8) 64 Process finished with exit code 0
四:标准库
关于标准库的资料:
- python 标准库
- python cookbook
- 模块官方文档 https://docs.python.org/3/library 以及使用指南 https://docs.python.org/3.3/tutorial/stdlib.html
- Doug Hellmann 的网站 Python Module of the week(https://pymotw.com/3/)
1.使用 setdefault() 和 defaultdict() 处理缺失的键
setdefault():如果键不存在于字典中,将会添加新的键并将值设为默认值(改变了字典)。如果字典中包含有给定键,则返回该键对应的值,否则返回为该键设置的值。
defaultdict():defaultdict() 返回一个字典,会自动给每个键(key)赋一个初始值
#coding=utf-8 d={"l1":1,"l2":2} print(d) #往d插入一组数据 d1=d.setdefault("l3",3) print(d1) #d1返回的结果为value值 print(d) d2=d.setdefault("l3",66) #l3已存在,返回已存在key的value值 print(d2) from collections import defaultdict def no_idea(): return "huahua" #使用工厂方法default_factory给所有key对应的value赋初始值,这些工厂方法有int(), long(), float(), complex(),str(), unicode(), basestring(), t=defaultdict(no_idea) t["d1"]=1 print(t["d2"]) print(t) #如果不用工厂方法,也可以使用自定义方法 m=defaultdict(lambda :"hub?") m["t1"] print(m)
打印信息:
{'l2': 2, 'l1': 1} 3 {'l2': 2, 'l3': 3, 'l1': 1} 3 huahua defaultdict(<function no_idea at 0x033F5230>, {'d2': 'huahua', 'd1': 1}) defaultdict(<function <lambda> at 0x033F51F0>, {'t1': 'hub?'})
例子:针对食物计数
#coding:utf-8 #方式1 from collections import defaultdict food_counter=defaultdict(int) for food in ["spam","eggs","spam"]: food_counter[food]+=1 print(food_counter) #方式2 d={} for food in ["spam","eggs","spam"]: if not food in d: d[food]=0 print(d) #d[food]+=1 d[food]=d[food]+1 print('food',d[food]) print(d)
打印结果:
defaultdict(<type 'int'>, {'eggs': 1, 'spam': 2}) {'spam': 0} ('food', 1) {'eggs': 0, 'spam': 1} ('food', 1) ('food', 2) {'eggs': 1, 'spam': 2}
2.使用 Counter() 计数
counter:计数器工具用来提供方便快捷的计数支持
from collections import Counter breakfast=['spam','spam','eggs','spam'] bc=Counter(breakfast) print(bc) #print(bc.most_common()) lunch=['eggs','eggs','bacon'] lc=Counter(lunch) print(lc) print(bc+lc)
打印结果:
Counter({'spam': 3, 'eggs': 1}) Counter({'eggs': 2, 'bacon': 1}) Counter({'eggs': 3, 'spam': 3, 'bacon': 1})
3.使用有序字典 OrderedDict() 按键排序
OrderedDict: 有序字典
from collections import OrderedDict #有序打印 quotes=OrderedDict([]) quotes=OrderedDict([("huahua","my name"),("yuruhao","huhu"),("qq","fere")]) for i in quotes: print(i)
打印结果:
huahua
yuruhao
qq
4.使用 pprint() 友好输出
from pprint import pprint qq={ "h":"huahua", "hao":"haohao" } pprint(qq)
打印结果:
{'h': 'huahua', 'hao': 'haohao'}
例子:判断回文字符串
#方式一 def x(word): from collections import deque dq=deque(word) while len(dq)>1: if dq.popleft()!=dq.pop(): return False return True print(x('a')) print(x('abcba')) print(x('adsd')) #方式二 def y(words): return words==words[::-1] #[::-1]:无头无尾,-1代表步长为-1,倒序 print(y("asdfdsa"))
打印结果:
None
True
False
True