Python的functools模块
(wrapperwrappedassigned = WRAPPER_ASSIGNMENTSupdated = WRAPPER_UPDATES):
类似咱们自己写的copy_preperties功能;
wrapper包装函数, wrapped被包装函数;
元组WRAPPER_ASSIGNMENTS中是要被覆盖的属性:模块名、名称、限定名、文档、参数注解
WRAPPER_ASSIGNMENTS = ()
元组WRAPPER_UPDATES中是要被更新的属性,__dict__属性字典:
WRAPPER_UPDATES = ('__dict__',)
增加一个__wrapped__属性,保留着wrapped函数;
import datetime, time, functools
def logger(fn):
# @copy_properties(fn)
def wrap(*args, **kwargs):
"""This is a wrapper"""
#before 功能增强
print("args={},kwargs={}".fORMat(args, kwargs))
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
#after 功能增强
duration = datetime.datetime.now() - start
print("function {} took {}s.".format(fn.__name__, duration.total_seconds()))
return ret
functools.update_wrapper(wrap, fn)# 这里就等价于@copy_properties(fn)
print("{} {}".format(id(wrap), id(fn)))# 这里是为了确认一下,add.__wrapped__到底是wrap,还是fn
return wrap
@logger
def add(x, y):
"""This is a function"""
print("======call add======")
time.sleep(2)
return x + y
print(add.__wrapped__)
print(id(add.__wrapped__))
其实按照源码来写的话,return wrap 可以直接写成return functools.update_wrapper(wrap, fn),为什么直接能这样写,自己看源码?
上面的方法,我们很少这样用,我们真正要用的是@functools.wraps(fn)
import datetime, time, functools
def logger(fn):
@functools.wraps(fn)
def wrap(*args, **kwargs):
"""This is a wrapper"""
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
duration = datetime.datetime.now() - start
print("function {} took {}s.".format(fn.__name__, duration.total_seconds()))
return ret
return wrap
@logger# add = logger(add)
def add(x, y):
"""This is a function"""
print("======call add======")
time.sleep(2)
return x + y
print(add.__name__, add.__wrapped__)
partial方法
偏函数,把函数部分的参数固定下来,相当于为部分的参数添加了一个固定的默认值,形成一个新的函数并返回;
从partial生成的新函数,是对原函数的封装;
举例说明:
import functools
import inspect
def add(x, y) -> int:
return x + y
print(inspect.signature(add)) #(x, y) -> int
newadd = functools.partial(add, y=5)
print(newadd(5))
print(newadd(5)) #TypeError: add() Got multiple values for argument 'y'
print(newadd(7, y=6))
print(newadd(y=6, x=10))
print(inspect.signature(newadd)) #这里是看一下新函数的签名,(x, *, y=5) -> int
更复杂一点:
import functools
import inspect
def add(x, y, *args) ->int:
print(args)
return x + y
newadd = functools.partial(add, 1, 3, 6, 5)
print(newadd(7))
print(newadd(7, 10))
# print(newadd(7, 10, y=20, x=10))###
print(newadd())
print(inspect.signature(newadd))
lru_cache:
@functools.lru_cache(maxsize=128, typed=False)
least-recently-used装饰器。lru,最近最少使用,cache缓存
如果maxsize设置为None,则禁用LRU功能,并且缓存可以当无限制增长。
当maxsize是二的幂时,LRU功能执行得最好。
如果typed设置为True,则不同类型的函数参数将单独缓存。例如,f(3)和f(3.0)将被视为具有不同结果的不同调用。
import functools, time
@functools.lru_cache()
def add(x, y, z=3):
time.sleep(z)
return x + y
print(add(4, 5))
print(add(4, 5))
print(add(4, 5))
print(add(4, 5))
#在ipython里看的效果会更清楚
相关文章