python-functools
目录functools模块用于高阶函数:作用与或者返回其它函数的函数。一般来说,对于该模块,任何可调用对象都可以视为一个函数
partial偏函数
偏函数,把函数部分的参数固定下来,相当于为部分的参数添加了一个固定的默认值,形成一个新的函数并返回
从partial生成的新函数, 并且可以像原始对象一样对待,这样可以简化函数调用。
partial(func,*args,**keywords)
仅仅作用函数,输入 函数,函数的参数,返回函数对象
主要作用:减少可调用对象的参数个数
## 等价于
def partial(func, /, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = {**keywords, **fkeywords}
return func(*args, *fargs, **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
案例1-普通使用
import functools
def add(x, y) -> int:
return x + y
newadd = functools.partial(add, y=5)
print(newadd(7)) # 12
print(newadd(7, y=6)) # 13
print(newadd(y=10, x=6)) # 16
可以在 json_serial_fallback
函数中添加类型判断来指定如何 json 序列化一个 Python 对象
def json_serial_fallback(obj):
"""
JSON serializer for objects not serializable by default json code
"""
if isinstance(obj, (datetime.datetime, datetime.date)):
return str(obj)
if isinstance(obj, bytes):
return obj.decode("utf-8")
raise TypeError ("%s is not JSON serializable" % obj)
json_dumps = partial(json.dumps, default=json_serial_fallback)
案例2-延迟执行
import time
import functools
class DelayFunc:
def __init__(self, duration, func):
self.duration = duration
self.func = func
def __call__(self, *args, **kwargs):
print(f'Wait for {self.duration} seconds...')
time.sleep(self.duration)
return self.func(*args, **kwargs)
def eager_call(self, *args, **kwargs):
print('Call without delay')
return self.func(*args, **kwargs)
def delay(duration):
"""
装饰器:推迟某个函数的执行。
同时提供 .eager_call 方法立即执行
"""
# 此处为了避免定义额外函数,
# 直接使用 functools.partial 帮助构造 DelayFunc 实例
return functools.partial(DelayFunc, duration)
@delay(duration=2)
def add(a, b):
return a+b
print(add(3,5))
# Wait for 2 seconds...
# 8
案例3-回调函数添加参数
partial() 通常被用来微调其他库函数所使用的回调函数的参数
def output_result(result, log=None):
if log is not None:
log.debug('Got: %r', result)
# A sample function
def add(x, y):
return x + y
if __name__ == '__main__':
import logging
from multiprocessing import Pool
from functools import partial
logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger('test') p = Pool()
p.apply_async(add, (3, 4), callback=partial(output_result, log=log))
p.close()
p.join()
partialmethod
partialmethod 仅作用于方法
其行为类似 partial但它被设计用作方法定义而非直接用作可调用对象。
class Cell(object):
def __init__(self):
self._alive = False
@property
def alive(self):
return self._alive
def set_state(self, state):
self._alive = bool(state)
set_alive = partialmethod(set_state, True)
set_dead = partialmethod(set_state, False)
c = Cell()
c.alive # False
c.set_alive()
c.alive # True
reduce
该函数的作用是将一个序列归纳为一个输出。
reduce(function, iterable[, initializer])
# 大致等于
def reduce(function, iterable, initializer=None):
it = iter(iterable)
if initializer is None:
value = next(it)
else:
value = initializer
for element in it:
value = function(value, element)
return value
from functools import reduce
def foo(x, y):
return x + y
l = range(1, 10)
res=reduce(foo, l)
print(res) # 45
res2=reduce(foo, l, 10) # 初始值=10
print(res2) # 55
wraps
任何时候你定义装饰器的时候,都应该使用 functools 库中的 @wraps 装饰器来注解底层包装函数
wraps 装饰器能消除装饰器带来的副作用
from functools import wraps
def decorator(func):
# @wraps(func)
def wrapper(*args, **kwargs):
"""wrapper func"""
return func(*args, **kwargs)
return wrapper
@decorator
def add(x, y):
"""add func"""
return x + y
print(add.__name__) # wrapper
print(add.__doc__) # wrapper func
print(add) # <function __main__.wrapper>
print(add(1,2))
# 函数的 __name__ 属性变成了 wrapper ,实际上add 函数整个变成了 decorator(add)
# 这就是装饰器函数的副作用
增加 @wrap 修饰,消除装饰器的副作用
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""wrapper func"""
return func(*args, **kwargs)
return wrapper
@decorator
def add(x, y):
"""add func"""
return x + y
print(add.__name__) # add
print(add.__doc__) # add func
print(add) # <function __main__.add>
print(add(1,2))
update_wrapper
update_wrapper
的作用与 wraps
类似,不过功能更加强大,换句话说,wraps
其实是 update_wrapper
的特殊化
实际上 wraps(wrapped)
相当于 partial(update_wrapper, wrapped=wrapped, **kwargs)
cache(user_function)
简单轻量级未绑定函数缓存
返回值与 lru_cache(maxsize=None)
相同,创建一个查找函数参数的字典的简单包装器。 因为它不需要移出旧值,所以比带有大小限制的 lru_cache()更小更快。
@cache
def factorial(n):
return n * factorial(n-1) if n else 1
factorial(10) # 3628800
factorial(12) # 479001600
lru_cache(maxsize)
LRU缓存,一个为函数提供缓存功能的装饰器,缓存 maxsize 组传入参数,在下次以相同参数调用时直接返回上一次的结果。用以节约高开销或I/O函数的调用时间。可以减少频繁调用相同的函数使用相同参数的I/O消耗。提升递归函数的执行效率
由于使用字典来缓存结果,因此传给该函数的位置和关键字参数必须为hashable
使用前提
同样的函数参数一定得到同样的结果
函数执行时间很长,且要多次执行
本质是函数调用的参数=>返回值
# 缓存同一个函数 相同参数执行的结果
@lru_cache(maxsize=128)
def work(n):
if n == 1:
return 1
else:
return work(n - 1) * n
print(work(6))
720
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
fiblist=[fib(n) for n in range(16)]
print(fiblist)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
singledispatch
要定义一个泛型函数,用装饰器 @singledispatch
来装饰它,函数根据传参类型不同,做出不同的操作.
from functools import singledispatch
@singledispatch
def typecheck(a):
print(a, type(a), 'a')
@typecheck.register(str)
def _(text):
print(text, type(text), 'str')
@typecheck.register(list)
def _(text):
print(text, type(text), 'list')
@typecheck.register(int)
def _(text):
print(text, type(text), 'int')
if __name__ == '__main__':
typecheck([1,2,3,4])
# [1, 2, 3, 4] <class 'list'> list
singledispatchmethod
class Negator:
@singledispatchmethod
def neg(self, arg):
raise NotImplementedError("Cannot negate a")
@neg.register
def _(self, arg: int):
return -arg
@neg.register
def _(self, arg: bool):
return not arg
参考资料
https://docs.python.org/zh-cn/3.10/library/functools.html?highlight=partial#
http://juzizhou.net/article/322
https://blog.csdn.net/xhtchina/article/details/128487830
标签:__,return,python,functools,add,func,print,def From: https://www.cnblogs.com/tian777/p/17773050.html