例子1
def make_avg():
series = [] #自由变量 ---
def ave(n): #|
series.append(n) #此间范围为闭包
total = sum(series) #|
return total/len(sries) ---
return ave
#控制台输入:
a = make_avg()
a(10)
a(11)
上例的方法效率不高,要把所有值存在历史记录里面,更好的方式是存储当前值和长度
例子2
def make_ave():
count=0
res = 0
def aver(n):
count += 1
res += n
return res / count
return aver
例子2在spyder提示错误无法编译,当count是数字或任何不可变的类型时,count+=1语句的作用其实与count=count+1一样,一次在aver中为count赋值了,会把count变成局部变量,所以count就不是自由变量了,不会保存在闭包中。而例子1没问题是因为调用append,并把它传给sum和len。
def make_ave():
count=0
res = 0
def aver(n):
nonlocal count, res
count += 1
res += n
return res / count
return aver
实现简单的装饰器
有时候我们觉得这个函数不够完善,我想在这个函数的基础上拓展一些额外的通用的功能,但是由于这个函数又很重要,不能直接侵入代码去改,加上可能其它的函数也需要这样一种功能,就是这样一个@xxx的东西
#简单的支持多参数装饰器
def deco(fun):
def wap(*args, **kargs):
time_start = time.time()
fun(*args, **kargs)
time_end = time.time()
print('running time :', time_end-time_start)
return wap
@deco
def Afun1(a, b,c):
time.sleep(1)
print('a+b+c=',a+b+c)
Afun1(1,3,4)
#7.7
'''
实现简单的装饰器
'''
import time
def clock(f):
def clocked(*args):
t0 = time.perf_counter()
result = f(*args)
ela = time.perf_counter() - t0
name = f.__name__
arg_str = ', '.join(repr(arg) for arg in args)
print('[%0.8fs] %s(%s) ->%r' % (ela, name, arg_str, result))
return result
return clocked
@clock
def snooze(sec):
time.sleep(sec)
@clock
def fact(n):
return 1 if n < 2 else n*fact(n-1)
if __name__=='__main__':
print('*'*40, 'calling snooze(.123)')
snooze(.123)
print('*'*40, 'calling snooze(6)')
fact(6)
其中:
上例代码等价于:
def snooze(sec):
time.sleep(sec)
clock(sbooze)
fact 保存的是clocked函数的引用,每次调用fact(n),执行的都是clocked(n),clocked大致做了下面几件事情:
例子3
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)
print(fibonacci(6))
#此代码非常耗时间,有很多重复计算
改良:
import functools
@functools.lru_cache()
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)
print result:
[0.00000030s] fibonacci(0) ->0
[0.00000030s] fibonacci(1) ->1
[0.00002180s] fibonacci(2) ->1
[0.00000060s] fibonacci(3) ->2
[0.00004260s] fibonacci(4) ->3
[0.00000040s] fibonacci(5) ->5
[0.00006430s] fibonacci(6) ->8
8
lru_cache(maxsize=128, typed = False)
maxsize指定存储多少调用结果,为2的次幂。typed参数如果设置为True,把不同参数分开保存。字典存储结果,所以参数必须可散列的。
例子1 实现的clock装饰器缺点:不支持关键字,遮盖了呗装饰的_name__和__doc__属性,使用functools.wraps()可以解决:
def clock(func):
@functools.wraps(func)
def clock(*args, **kargs):
python不支持重载方法函数,所以使用singledispatch装饰器把整体方案拆分成多个模块。
from functools import singledispatch
from collections import abc
import numbers
import html
@singledispatch #标记处理object类型的基函数
def htmlize(obj):
content = html.escape(repr(obj))
return '{}
'.format(content)
@htmlize.register(str)
def _(text): #专用名称函数无关紧要
content = html.escape(text).replace('\n','
\n')
return '{0}
'.format(content)
@htmlize.register(numbers.Integral)
def _(n):
return '{0}(0x{0:x})
'.format(n)