版权声明:qq:1263351411 https://blog.csdn.net/u013008795/article/details/89467690
python常用模块简介
functools模块
-
update_wrapper #修改装饰函数的属性
- 原码如下:
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__', '__annotations__') WRAPPER_UPDATES = ('__dict__',) def update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): for attr in assigned: try: value = getattr(wrapped, attr) except AttributeError: pass else: setattr(wrapper, attr, value) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) #用wrapped的字典__dict__更新wrapper的字典__dict__ wrapper.__wrapped__ = wrapped #新增一个属性,记录原函数 return wrapper
-
wraps 结合update_wrapper修改装饰函数的属性
*原码如下:def wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)
-
reduce(function,sequence[,initial])->value #缩减计算
- function 函数,
- sequence 可迭代对象,需要做递减计算的可迭代对象
- initial 初始值,如果没有,默认从sequence中取出第一个值做初始值。
- 相关原码:
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
-
partial->function #偏函数,吧函数部分参数固定下来,相当于为部分的参数添加了一个固定的默认值,形成一个新的函数并返回。
- partial生成的新函数是对原函数的封装。
- 伪代码示例
def partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = keywords.copy() # newkeywords.update(fkeywords) #更新关键字参数 return func(*args, *fargs, **newkeywords) #注意,调用原函数时,先放的是位置参数,然后放的是再次传入的位置参数,最后放的是更新后的关键字参数 newfunc.func = func #新增一个属性,记录原函数 newfunc.args = args #新增一个属性,记录位置参数 newfunc.keywords = keywords #新增一个属性记录关键字参数 return newfunc #返回内建函数。
- partial例子代码:
import functools,inspect def add(x,y)->int: return x+y newadd = functools.partial(add,y=3) print(newadd(5)) print(newadd(5,y=9)) print(newadd(y=8,x=7)) print(inspect.signature(newadd))
-
lru_cache(maxsize=128,typed=False) #是个装饰器,为函数生成缓存机制
- Least-recently-used装饰器,lru最近最少使用。cache缓存
- 如果maxsize设置为None,则禁用LRU功能,并且缓存可以无限制增长。当maxsize是二的次幂时,LRU功能执行得最好
- 如果typed设置为True,则不同类型的函数参数将单独缓存。例如:f(3)和f(3.0)将被视为具有不同结果的不同调用。其原理是内部记录的每个参数的类型,计算根据参数字符串+参数类型计算hash值。
- lru_cache装饰器使用前提
- 同样的函数参数一定得到相同的结果
- 函数执行时长很长,且要多次执行
- lru_cache本质上是用一个字典记录了函数调用参数组成的字符串做key,和计算的值做value,如果下次调用发现参数一直,就直接从字典中取出对应的值返回。避免重复计算
- 缺点:
- 不支持缓存过期,key无法过期、失效
- 不支持清除操作
- 不支持分布式,是一个单机的缓存
- 使用场景,单机上需要空间换时间的地方,可以用缓存来将计算变成快速查询
- 简单示例:用公式求斐波拉系数列。使用缓存
import functools @functools.lru_cache(maxsize=50) def getnum(n): return 1 if n<3 else getnum(n-1)+getnum(n-2)
functools模块经典应用
- 函数运行时长统计
def gdy_time(fn):
"""
时间统计,统计函数执行时间
:param fn: 需要装饰的函数
:return: 包装后的fn
"""
@functools.wraps(fn)
def wrapper(*args,**kwargs):
start = datetime.datetime.now()
req = fn(*args,**kwargs)
timeout = datetime.datetime.now() - start
gdy_print("{}方法耗时:{},args={},kwargs={},\n执行结果:req={}".format(fn.__name__,timeout.total_seconds(),args,kwargs,req))
return req
return wrapper
inspect模块
- signature(callable)-><class ‘inspect.Signature’> 获取签名(函数签名包含了一个函数的信息,包括函数名,它的产生类型、它所在的类和名称空间及其他信息)
- 签名返回类型为inspect.Signature类型
- parameters属性,记录了函数中定义是注解和参数。parameters实际上是一个字典。
- annotation 可以获取parameters对应value值的类型,即定义是注解说明的类型。
- parameters属性,记录了函数中定义是注解和参数。parameters实际上是一个字典。
- 简单示例
import inspect def add(x,y:int=5,*args,k,z=4,**kwargs): return x+y sig = inspect.signature(add) #获取函数签名 print(sig,type(sig)) #函数签名 print("params =",sig.parameters) #记录参数 print(sig.parameters['y'],type(sig.parameters['y'])) print(sig.parameters['y'].annotation) #y参数的类型 print(sig.parameters['x']) print(sig.parameters['x'].annotation) #如果定义函数参数时没添加注解类型,默认为inspect._empty空类型 print(sig.parameters['args']) print(sig.parameters['args'].annotation) print(sig.parameters['kwargs']) print(sig.parameters['kwargs'].annotation)
- 签名返回类型为inspect.Signature类型
- isfunction(name)-> True|False #是否是函数
- ismethod(name)-> True|False #是否是类方法
- isgenerator(name)-> True|False #是否是生成器对象
- isgeneratorfunction(name)-> True|False #是否是生成器函数
- isclass(name)-> True|False #是否是类
- ismodule(name)-> True|False #是否是模块
- isbuiltin(name)-> True|False #是否是内建对象
- Parameter 对象,是一个类
- 类的属性有name,annotation,default,empty,kind保存在元组中是可读的
- name:参数名字
- annotation:参数注解。(有时候可能没有定义)
- default:参数缺省值,(有时候可能没有定义)
- empty:特殊类,用来标记default属性或者注释annotation属性的空值
- kind:实参如何绑定到形参,就是形参的类型
- POSITIONAL_ONLY,值必须是位置参数提供
- POSITIONAL_OR_KEYWORD,值可以作为关键字或者位置参数提供
- VAR_POSITIONAL,可变位置参数,对应*args
- KEYWORD_ONLY,keyword-only参数,对应* 或者 *args之后出现的费可变关键字参数
- VAR_KEYWORD,可变关键字参数,对应**kwargs
inspect模块经典应用
- 参数检查
def gdy_paramCheck(fn):
"""
参数检查
:param fn: 需要检查的函数
:return: 包装后的fn
"""
@functools.wraps(fn)
def _gdy_paramCheck(*args,**kwargs):
params = inspect.signature(fn).parameters #对函数签名,获取参数注解字典
for ag,(k,v) in zip(args,params.items()): ##检查位置参数
v:inspect.Parameter = v #利用参数注解,告诉编译器v是Parameter类型。本行可以删除,只是帮助编译器给出提示
# print(k=="args")
if k == "args": break #如果碰到args收集多个位置参数,就直接跳出循环。
if v.annotation != inspect._empty and not isinstance(ag,v.annotation):
# raise TypeError(""{}={},参数类型错误!错误类型:{},类型应为:{}".format(k,ag,type(ag),v.annotation))
print("{}={},参数类型错误!错误类型:{},类型应为:{}".format(k,ag,type(ag),v.annotation))
return
for k,v in kwargs.items():
key:inspect.Parameter = params[k] #利用参数注解,告诉编译器key是Parameter类型。本行可以删除,只是帮助编辑器能给出提示
if key.empty != key.annotation and not isinstance(v,key.annotation):
# raise TypeError("{}={},参数错误!错误类型:{}类型应为:{}".format(k,v, type(v),key.annotation))
print("{}={},参数错误!错误类型:{}类型应为:{}".format(k,v, type(v),key.annotation))
return
return fn(*args,**kwargs)
return _gdy_paramCheck