1.参数注解
1.1函数注解
Python 3.5引入
对函数的参数进行类型注解
对函数的返回值进行类型注解
只对函数参数做一个辅助的说明,并不对函数参数进行类型检查
提供给第三方工具,做代码分析,发现隐藏的bug
函数注解的信息,保存在__annotations__属性中
def add(x:int,y:int)->int:
return x + y
add.__annotations__
{'x': int, 'y': int, 'return': int}
__annotations__属性是一个字典,其中包括返回值类型的声明。假设要做位置参数的判断,无
法和字典中的声明对应。使用inspect模块
1.2 inspet模块
提供获取对象信息的函数,可以检查函数和类、类型检查
signature(callable),获取签名(函数签名包含了一个函数的信息,包括函数名、它的参数类型、它
所在的类和名称空间及其他信息)
inspect模块
Parameter对象
保存在元组中,是只读的
name,参数的名字
annotation,参数的注解,可能没有定义
default,参数的缺省值,可能没有定义
empty,特殊的类,用来标记default属性或者注释annotation属性的空值
kind,实参如何绑定到形参,就是形参的类型
POSITIONAL_ONLY,值必须是位置参数提供 (其实是没有的)
POSITIONAL_OR_KEYWORD,值可以作为关键字或者位置参数提供
VAR_POSITIONAL,可变位置参数,对应args
KEYWORD_ONLY,keyword-only参数,对应或者*args之后的出现的非可变关键字参数
VAR_KEYWORD,可变关键字参数,对应**kwargs
1.3 业务应用
import inspect
def check(fn):
def wrapper(*args, **kwargs):
sig = inspect.signature(fn)
params = sig.parameters
values = list(params.values())
for i ,p in enumerate(args):
param = values[i]
if param.annotation is not param.empty and not isinstance(p,param.annotation):
print(p,'!==',values[i].annotation)
for k,v in kwargs.items():
if params[k].annotation is not inspect._empty and not isinstance(v,params[k].annotation):
print(k,v,"!===",params[k].annotation)
return fn(*args,**kwargs)
return wrapper
@check
def add(x,y:int = 7)-> int:
return x + y
add(20,10)
add(25,y = 10)
add(y = 10,x = 11)
2. Python之functools
2.1 reduce方法
reduce方法,顾名思义就是减少
reduce(function, sequence[, initial]) -> value
可迭代对象不能为空;初始值没提供就在可迭代对象中取一个元素
from functools import reduce
nums = [6, 9, 4, 2, 4, 10, 5, 9, 6, 9]
print(nums)
print(sum(nums))
print(reduce(lambda val, x: val + x, nums))
------------>
[6, 9, 4, 2, 4, 10, 5, 9, 6, 9]
64
64
2.2 partial方法
偏函数,把函数部分的参数固定下来,相当于为部分的参数添加了一个固定的默认值,形成一个新的函数并返回
从partial生成的新函数,是对原函数的封装
举例:
import functools
def add(x,y) ->int:
return x + y
newadd = functools.partial(add, y = 5)
print(newadd(7))
print(newadd(7,y =6))
print(newadd(y = 10,x = 6))
import inspect
print(inspect.signature(newadd))
------------->
12
13
16
(x, *, y=5) -> int
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
def add(x,y):
return x+y
foo = partial(add,4)
foo(5)
2.3 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
import time
@functools.lru_cache()
def add(x, y, z = 3):
time.sleep(z)
return x + y
add(4,5)
functools._make_key((4,6),{"z":3},False)
functools._make_key(tuple(),{"z":3,"x":4,"y":6},False)
functools._make_key((3,),{"z":3,"x":4,"y":6},True)
---------------------->
[4, 6, <object at 0x1fc291bb0b0>, 'z', 3]
[<object at 0x1fc291bb0b0>, 'z', 3, 'x', 4, 'y', 6]
[3, <object at 0x1fc291bb0b0>, 'z', 3, 'x', 4, 'y', 6, int, int, int, int]
lru_cache装饰器
斐波那契数列递归方法的改造
import functools
@functools.lru_cache(maxsize = 30)
def fib(n):
return 1 if n < 3 else fib(n-1)+fib(n-2)
fib(210)
2.4 lru_cache装饰器应用
使用前提
同样的函数参数一定得到同样的结果
函数执行时间很长,且要多次执行
本质是函数调用的参数=>返回值
缺点
不支持缓存过期,key无法过期、失效
不支持清除操作
不支持分布式,是一个单机的缓存
适用场景,单机上需要空间换时间的地方,可以用缓存来将计算变成快速的查询