python总结5(迭代器、生成器、装饰器)
2020-07-13 04:31
77 查看
转链接:GitHub链接
四、Python三大利器
Python中的三大利器包括:
迭代器,
生成器,
装饰器,利用好它们才能开发出最高性能的Python程序,涉及到的内置模块
itertools提供迭代器相关的操作。此部分收录有意思的例子共计
15例。
142 寻找第n次出现位置
def search_n(s, c, n): size = 0 for i, x in enumerate(s): if x == c: size += 1 if size == n: return i return -1 print(search_n("fdasadfadf", "a", 3))# 结果为7,正确 print(search_n("fdasadfadf", "a", 30))# 结果为-1,正确
143 斐波那契数列前n项
def fibonacci(n): a, b = 1, 1 for _ in range(n): yield a a, b = b, a + b list(fibonacci(5)) # [1, 1, 2, 3, 5]
144 找出所有重复元素
from collections import Counter def find_all_duplicates(lst): c = Counter(lst) return list(filter(lambda k: c[k] > 1, c)) find_all_duplicates([1, 2, 2, 3, 3, 3]) # [2,3]
145 联合统计次数
Counter对象间可以做数学运算
from collections import Counter a = ['apple', 'orange', 'computer', 'orange'] b = ['computer', 'orange'] ca = Counter(a) cb = Counter(b) #Counter对象间可以做数学运算 ca + cb # Counter({'orange': 3, 'computer': 2, 'apple': 1}) # 进一步抽象,实现多个列表内元素的个数统计 def sumc(*c): if (len(c) < 1): return mapc = map(Counter, c) s = Counter([]) for ic in mapc: # ic 是一个Counter对象 s += ic return s #Counter({'orange': 3, 'computer': 3, 'apple': 1, 'abc': 1, 'face': 1}) sumc(a, b, ['abc'], ['face', 'computer'])
146 groupby单字段分组
天气记录:
a = [{'date': '2019-12-15', 'weather': 'cloud'}, {'date': '2019-12-13', 'weather': 'sunny'}, {'date': '2019-12-14', 'weather': 'cloud'}]
按照天气字段
weather分组汇总:
from itertools import groupby for k, items in groupby(a,key=lambda x:x['weather']): print(k)
输出结果看出,分组失败!原因:分组前必须按照分组字段
排序,这个很坑~
cloud sunny cloud
修改代码:
a.sort(key=lambda x: x['weather']) for k, items in groupby(a,key=lambda x:x['weather']): print(k) for i in items: print(i)
输出结果:
cloud {'date': '2019-12-15', 'weather': 'cloud'} {'date': '2019-12-14', 'weather': 'cloud'} sunny {'date': '2019-12-13', 'weather': 'sunny'}
147 itemgetter和key函数
注意到
sort和
groupby所用的
key函数,除了
lambda写法外,还有一种简写,就是使用
itemgetter:
a = [{'date': '2019-12-15', 'weather': 'cloud'}, {'date': '2019-12-13', 'weather': 'sunny'}, {'date': '2019-12-14', 'weather': 'cloud'}] from operator import itemgetter from itertools import groupby a.sort(key=itemgetter('weather')) for k, items in groupby(a, key=itemgetter('weather')): print(k) for i in items: print(i)
结果:
cloud {'date': '2019-12-15', 'weather': 'cloud'} {'date': '2019-12-14', 'weather': 'cloud'} sunny {'date': '2019-12-13', 'weather': 'sunny'}
148 groupby多字段分组
itemgetter是一个类,
itemgetter('weather')返回一个可调用的对象,它的参数可有多个:
from operator import itemgetter from itertools import groupby a.sort(key=itemgetter('weather', 'date')) for k, items in groupby(a, key=itemgetter('weather')): print(k) for i in items: print(i)
结果如下,使用
weather和
date两个字段排序
a,
cloud {'date': '2019-12-14', 'weather': 'cloud'} {'date': '2019-12-15', 'weather': 'cloud'} sunny {'date': '2019-12-13', 'weather': 'sunny'}
注意这个结果与上面结果有些微妙不同,这个更多是我们想看到和使用更多的。
149 sum函数计算和聚合同时做
Python中的聚合类函数
sum,
min,
max第一个参数是
iterable类型,一般使用方法如下:
a = [4,2,5,1] sum([i+1 for i in a]) # 16
使用列表生成式
[i+1 for i in a]创建一个长度与
a一行的临时列表,这步完成后,再做
sum聚合。
试想如果你的数组
a长度十百万级,再创建一个这样的临时列表就很不划算,最好是一边算一边聚合,稍改动为如下:
a = [4,2,5,1] sum(i+1 for i in a) # 16
此时
i+1 for i in a是
(i+1 for i in a)的简写,得到一个生成器(
generator)对象,如下所示:
In [8]:(i+1 for i in a) OUT [8]:<generator object <genexpr> at 0x000002AC7FFA8CF0>
生成器每迭代一步吐出(
yield)一个元素并计算和聚合后,进入下一次迭代,直到终点。
150 list分组(生成器版)
from math import ceil def divide_iter(lst, n): if n <= 0: yield lst return i, div = 0, ceil(len(lst) / n) while i < n: yield lst[i * div: (i + 1) * div] i += 1 list(divide_iter([1, 2, 3, 4, 5], 0)) # [[1, 2, 3, 4, 5]] list(divide_iter([1, 2, 3, 4, 5], 2)) # [[1, 2, 3], [4, 5]]
151 列表全展开(生成器版)
#多层列表展开成单层列表 a=[1,2,[3,4,[5,6],7],8,["python",6],9] def function(lst): for i in lst: if type(i)==list: yield from function(i) else: yield i print(list(function(a))) # [1, 2, 3, 4, 5, 6, 7, 8, 'python', 6, 9]
152 测试函数运行时间的装饰器
#测试函数执行时间的装饰器示例 import time def timing_func(fn): def wrapper(): start=time.time() fn() #执行传入的fn参数 stop=time.time() return (stop-start) return wrapper @timing_func def test_list_append(): lst=[] for i in range(0,100000): lst.append(i) @timing_func def test_list_compre(): [i for i in range(0,100000)] #列表生成式 a=test_list_append() c=test_list_compre() print("test list append time:",a) print("test list comprehension time:",c) print("append/compre:",round(a/c,3)) test list append time: 0.0219423770904541 test list comprehension time: 0.007980823516845703 append/compre: 2.749
153 统计异常出现次数和时间的装饰器
写一个装饰器,统计某个异常重复出现指定次数时,经历的时长。
import time import math def excepter(f): i = 0 t1 = time.time() def wrapper(): try: f() except Exception as e: nonlocal i i += 1 print(f'{e.args[0]}: {i}') t2 = time.time() if i == n: print(f'spending time:{round(t2-t1,2)}') return wrapper
关键词
nonlocal常用于函数嵌套中,声明变量i为非局部变量;
如果不声明,
i+=1表明
i为函数
wrapper内的局部变量,因为在
i+=1引用(reference)时,
i未被声明,所以会报
unreferenced variable的错误。
使用创建的装饰函数
excepter,
n是异常出现的次数。
共测试了两类常见的异常:
被零除和
数组越界。
n = 10 # except count @excepter def divide_zero_except(): time.sleep(0.1) j = 1/(40-20*2) # test zero divived except for _ in range(n): divide_zero_except() @excepter def outof_range_except(): a = [1,3,5] time.sleep(0.1) print(a[3]) # test out of range except for _ in range(n): outof_range_except()
打印出来的结果如下:
division by zero: 1 division by zero: 2 division by zero: 3 division by zero: 4 division by zero: 5 division by zero: 6 division by zero: 7 division by zero: 8 division by zero: 9 division by zero: 10 spending time:1.01 list index out of range: 1 list index out of range: 2 list index out of range: 3 list index out of range: 4 list index out of range: 5 list index out of range: 6 list index out of range: 7 list index out of range: 8 list index out of range: 9 list index out of range: 10 spending time:1.01
154 测试运行时长的装饰器
#测试函数执行时间的装饰器示例 import time def timing(fn): def wrapper(): start=time.time() fn() #执行传入的fn参数 stop=time.time() return (stop-start) return wrapper @timing def test_list_append(): lst=[] for i in range(0,100000): lst.append(i) @timing def test_list_compre(): [i for i in range(0,100000)] #列表生成式 a=test_list_append() c=test_list_compre() print("test list append time:",a) print("test list comprehension time:",c) print("append/compre:",round(a/c,3)) # test list append time: 0.0219 # test list comprehension time: 0.00798 # append/compre: 2.749
155 装饰器通俗理解
再看一个装饰器:
def call_print(f): def g(): print('you\'re calling %s function'%(f.__name__,)) return g
使用
call_print装饰器:
@call_print def myfun(): pass @call_print def myfun2(): pass
myfun()后返回:
In [27]: myfun() you're calling myfun function In [28]: myfun2() you're calling myfun2 function
使用call_print
你看,
@call_print放置在任何一个新定义的函数上面,都会默认输出一行,你正在调用这个函数的名。
这是为什么呢?注意观察新定义的
call_print函数(加上@后便是装饰器):
def call_print(f): def g(): print('you\'re calling %s function'%(f.__name__,)) return g
它必须接受一个函数
f,然后返回另外一个函数
g.
装饰器本质
本质上,它与下面的调用方式效果是等效的:
def myfun(): pass def myfun2(): pass def call_print(f): def g(): print('you\'re calling %s function'%(f.__name__,)) return g
下面是最重要的代码:
myfun = call_print(myfun) myfun2 = call_print(myfun2)
大家看明白吗?也就是call_print(myfun)后不是返回一个函数吗,然后再赋值给myfun.
再次调用myfun, myfun2时,效果是这样的:
In [32]: myfun() you're calling myfun function In [33]: myfun2() you're calling myfun2 function
你看,这与装饰器的实现效果是一模一样的。装饰器的写法可能更加直观些,所以不用显示的这样赋值:
myfun = call_print(myfun),
myfun2 = call_print(myfun2),但是装饰器的这种封装,猛一看,有些不好理解。
156 定制递减迭代器
#编写一个迭代器,通过循环语句,实现对某个正整数的依次递减1,直到0. class Descend(Iterator): def __init__(self,N): self.N=N self.a=0 def __iter__(self): return self def __next__(self): while self.a<self.N: self.N-=1 return self.N raise StopIteration descend_iter=Descend(10) print(list(descend_iter)) [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
核心要点:
1
__next__名字不能变,实现定制的迭代逻辑
2
raise StopIteration:通过 raise 中断程序,必须这样写
相关文章推荐
- python05 - 迭代器,生成器,装饰器
- 循序渐进Python3(四) -- 装饰器、迭代器和生成器
- Python基础知识点——装饰器、生成器、迭代器
- python学习-Day15-python生成式和生成器、迭代器、装饰器
- python学习笔记四 迭代器,生成器,装饰器(基础篇)
- python 学习2:生成器,迭代器,装饰器
- python的迭代器、生成器、装饰器
- Python学习总结-迭代器与生成器
- python迭代器、生成器、装饰器
- python 学习2:生成器,迭代器,装饰器
- python基础教程总结8——特殊方法,属性,迭代器,生成器,八皇后问题
- 有关python函数总结;可迭代对象、生成器与迭代器的区别;相关函数
- Python生成器、迭代器、装饰器
- 简述python三神器——装饰器、迭代器、生成器
- 装饰器、生成器、迭代器、及python中内置函数的使用
- 【总结】python的生成器和迭代器
- python核心高级学习总结8------动态性、__slots__、生成器、迭代器、装饰、闭包
- python迭代器、生成器、装饰器之生成器
- Python生成器与迭代器的总结
- python 生成器 迭代器 用法最全总结(7种典型的用法)