装饰器

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无法过期、失效
不支持清除操作
不支持分布式,是一个单机的缓存
适用场景,单机上需要空间换时间的地方,可以用缓存来将计算变成快速的查询

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值