Python functools模块应用于高阶函数,即参数或返回值作为其他函数的函数。
Python functools——高阶函数
以下函数需要Python 3.8,Python3 在线工具:
cached_property()
singledispatchmethod
查看版本:
import sys
print(sys.version)
缓存属性cached_property
计算一次就被缓存
from functools import cached_property
class DataSet:
def __init__(self, sequence_of_numbers):
self._data = sequence_of_numbers
@cached_property
def stdev(self):
return statistics.stdev(self._data)
@cached_property
def variance(self):
return statistics.variance(self._data)
函数缓存装饰器lru_cache
斐波那契数列的递推公式如下,在编程中最直接的实现方式是使用递归,如果能将每一步的计算结果缓存下来,那计算效率肯定更高
使用functools
模块中的lru_cache()
,最久未使用(LRU)缓存算法
PS:该算法在计算结果相同时有用,如time()
或random()
之类的函数是没有用的
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
result = [fib(i) for i in range(16)]
print(result)
print(fib.cache_info()) # 查看命中和未命中次数
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
# CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
计算n=16的斐波那契数列的情况下,快250倍。使用了缓存后,n=1000也能轻松计算出来。
自动实现全比较total_ordering
实现其中一个: __lt__()
, __le__()
, __gt__()
, __ge__()
,自动实现剩余方法。
注:
- 此类需要支持
__eq__()
- 执行速度更慢
@total_ordering
class Student:
def __init__(self, firstname, lastname):
self.firstname = firstname
self.lastname = lastname
def __eq__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) == (other.lastname.lower(), other.firstname.lower()))
def __lt__(self, other):
return ((self.lastname.lower(), self.firstname.lower()) < (other.lastname.lower(), other.firstname.lower()))
a = Student(firstname='a', lastname='bbb')
b = Student(firstname='b', lastname='bbb')
print(a < b) # True
print(a <= b) # True
print(a > b) # False
print(a >= b) # False
print(a != b) # True
print(a == b) # False
print(b == b) # True
固化参数partial
将部分函数参数固化下来
basetwo = partial(int, base=2) # basetwo相当于int(x, base=2),将参数base=2固化下来
basetwo('10010')
# 18
print1 = partial(print, end=' ') # print1相当于print(x, end=' '),将参数end=' '固化下来
print1('Hello', 'World!')
# Hello World!
用于定义方法的固化参数partialmethod
将部分函数参数固化下来,用作方法定义
class Cell:
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.set_alive()
print(c.alive)
# True
累积应用reduce
从左到右应用直至算出最终值
print(reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])) # 相当于((((1+2)+3)+4)+5)
# 15
函数重载singledispatch
根据第一个参数的类型进行重载
@singledispatch
def mul(a, b):
return a * b
@mul.register(str)
def _(a: str, b: str):
return int(a) * int(b)
print(mul(1, 2)) # 2
print(mul(1.5, 2.5)) # 3.75
print(mul(1, 1.0)) # 1.0
print(mul('1', '2')) # 2
用于定义方法的函数重载singledispatchmethod
from functools import singledispatchmethod
class Negator:
@singledispatchmethod
def neg(self, arg):
raise NotImplemented
@neg.register
def _(self, arg: int):
return -arg
@neg.register
def _(self, arg: bool):
return not arg
neg = Negator()
print(neg.neg(5)) # -5
print(neg.neg(True)) # False
更新包装器wraps
自动更新包装器,使其拥有原函数的文档字符串等信息,包括:__module__
, __name__
, __qualname__
, __annotations__
, __doc__
不加该装饰器,原函数的信息会消失:
def show_args(f):
# @wraps(f)
def wrapper(*args, **kwargs):
print('调用函数 {} 参数为 {} {}'.format(f.__name__, args, kwargs))
return f(*args, **kwargs)
return wrapper
@show_args
def add(a: int, b: int) -> int:
"""加法"""
return a + b
print(add(5, 1))
print(add.__doc__)
print(add.__name__)
# 调用函数 add 参数为 (5, 1) {}
# 6
# None
# wrapper
加上后保留原函数信息
def show_args(f):
@wraps(f)
def wrapper(*args, **kwargs):
print('调用函数 {} 参数为 {} {}'.format(f.__name__, args, kwargs))
return f(*args, **kwargs)
return wrapper
@show_args
def add(a: int, b: int) -> int:
"""加法"""
return a + b
print(add(5, 1))
print(add.__doc__)
print(add.__name__)
# 调用函数 add 参数为 (5, 1) {}
# 6
# 加法
# add