再探Python:再次学习以补充知识。这次学习聚焦于巩固Python装饰器,填补之前的知识空白。
装饰器
| def logger(fn): |
| def wrapper(*args,**kwargs): |
| print('调用前增强') |
| ret = fn(*args,**kwargs) |
| print('调用后增强') |
| return ret |
| return wrapper |
| |
| @logger |
| def add(x,y): |
| return x + y |
| |
| print(add(100,200)) |
| ''' |
| 1. 上例中的装饰器语法,称为无参装饰器 |
| 2. @符号后面是一个函数名,表示将该函数作为装饰器使用 |
| 3. 虽然是无参装饰器,但是@后的函数本质上是单参数函数 |
| 4. 上例的logger函数是一个高阶函数 |
| ''' |
无参装饰器
| def add(x,y): |
| return x + y |
| |
| def logger(fn,x,y): |
| print(fn.__name__,x,y) |
| ret = fn(x,y) |
| return ret |
| |
| print(logger(add,10,20)) |
| def add(x,y): |
| return x + y |
| |
| def logger(fn): |
| def inner(*args,**kwargs): |
| print(fn.__name__,args,kwargs) |
| print('执行前可以做的事情,增强') |
| ret = fn(*args,**kwargs) |
| print('执行后可以做的事情,增强') |
| return ret |
| return inner |
| logger_add = logger(add)(4,y=100) |
| print(logger_add) |
| |
| add (4,) {'y': 100} |
| 执行前可以做的事情,增强 |
| 执行后可以做的事情,增强 |
| 104 |
| |
| @logger |
| def add(x,y): |
| return x + y |
| |
| |
| |
| |
带参装饰器
| def add(x,y): |
| return x + y |
| |
| def logger(fn): |
| def inner(*args,**kwargs): |
| ''' |
| add description |
| 这个warpper函数的描述 |
| ''' |
| print(fn.__name__,args,kwargs) |
| print('执行前可以做的事情,增强') |
| ret = fn(*args,**kwargs) |
| print('执行后可以做的事情,增强') |
| return ret |
| return inner |
| logger_add = logger(add)(4,y=100) |
| |
| print(logger_add) |
| |
| @logger |
| def add(x,y): |
| ''' |
| add description |
| 这add函数的描述 |
| ''' |
| return x + y |
| |
| help(add) |
| |
| |
| |
| |
| |
| from functools import wraps |
| def logger(fn): |
| @wraps(fn) |
| def inner(*args,**kwargs): |
| ''' |
| add description |
| 这个warpper函数的描述 |
| ''' |
| print(fn.__name__,args,kwargs) |
| print('执行前可以做的事情,增强') |
| ret = fn(*args,**kwargs) |
| print('执行后可以做的事情,增强') |
| return ret |
| return inner |
| logger_add = logger(add)(4,y=100) |
| print(logger_add) |
| |
| |
| @logger |
| def add(x,y:int): |
| ''' |
| add description |
| # 这add函数的描述 |
| ''' |
| return x + y |
| |
| print(add.__name__, add.__doc__, add.__annotations__) |
| |
| |
| |
| |
| |
| @logger |
| def add(x,y:int): |
| return x + y |
| |
| @logger() |
| def add(x,y:int): |
| return x + y |
| |
| @logger(1,2) |
| def add(x,y:int): |
| return x + y |
| import datetime |
| |
| from functools import wraps,update_wrapper |
| def logger(warpped): |
| print('---------',warpped.__name__) |
| @wraps(warpped) |
| def wrapper(*args,**kwargs): |
| start = datetime.datetime.now() |
| ret = warpped(*args,**kwargs) |
| dalta = (datetime.datetime.now() - start).total_seconds() |
| print("{} tooks {}s".format(warpped.__name__,dalta)) |
| return ret |
| return wrapper |
| @logger |
| def add(x,y): |
| return x + y |
| |
| @logger |
| def sub(x,y): |
| return x - y |
| |
| |
| |
| |
| |
| |
annotation注解
| def add(x:int,y:int) -> int: |
| """ |
| :param x: int |
| :param y: int |
| :return: int |
| """ |
| return x + y |
| |
| print(add.__annotations__) |
| |
| |
| |
| |
| |
| a:list = [1,2,3] |
| a. 就可以开始补全 |
| |
| |
| import inspect |
| inspect.isfunction(add) |
| def add(x:int,/,y:int, *args, m=100, **kwargs) -> int: |
| """ |
| :param x: int |
| :param y: int |
| :return: int |
| """ |
| return x + y |
| |
| |
| |
| |
| |
| |
| |
| import inspect |
| |
| params = inspect.signature(add).parameters |
| |
| for k,v in params.items(): |
| print(k, v.name , v.default , v.annotation , v.kind) |
| |
| |
| |
| |
| |
| |
| import inspect |
| from functools import wraps |
| |
| def check(fn): |
| @wraps(fn) |
| def wrapper(*args, **kwargs): |
| params = inspect.signature(fn).parameters |
| |
| for v,p in zip(args, params.values()): |
| if p.annotation != p.empty and not isinstance(v, p.annotation): |
| print("{} = {} is not OK. args~~~".format(p.name, v)) |
| for k, v in kwargs.items(): |
| if params[k].annotation !=inspect._empty and not isinstance(v, params[k].annotation): |
| print("{} = {} is not OK. kwargs~~~".format(k, v)) |
| ret = fn(*args, **kwargs) |
| |
| return ret |
| return wrapper |
| |
| @check |
| def add(x:int,y:int) -> int: |
| return x + y |
| |
| print(add("4", "8")) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| names = ['Alice', 'Bob', 'Charlie'] |
| ages = [25, 30, 35] |
| |
| |
| zipped_data = zip(names, ages) |
| |
| |
| for item in zipped_data: |
| print(item) |
| |
| ('Alice', 25) |
| ('Bob', 30) |
| ('Charlie', 35) |
直接插入排序

核心算法
- 结果可以为升序或降序排列,默认升序排列。以升序为例
- 扩大有序区,减少无序区。图中绿色部分就是增大的有序区,黑色部分就是减小的无序区;
- 增加一个哨兵位,图中最左端红色数字,其中放置每一趟比较数值;
- 将哨兵位数值与有序区数值从右到左依次比较,找到哨兵位数值合适的入点;
核心思想
| |
| |
| nums = [1,9,8,5,6] |
| nums = [None] + nums |
| length = len(nums) |
| print(nums[1:],length) |
| count_move = 0 |
| |
| for i in range(2,length): |
| nums[0] = nums[i] |
| j = i - 1 |
| if nums[j] > nums[0]: |
| while nums[j] > nums[0]: |
| nums[j+1] = nums[j] |
| j -= 1 |
| nums[j+1] = nums[0] |
| count_move += 1 |
| |
| print(nums[1:],count_move) |
| |
| |
| |
| from functools import reduce,partial,lru_cache |
| |
| |
| def fn(x, y): |
| print(x, y ) |
| return x + y |
| |
| reduce(fn,range(5)) |
| |
| |
| |
| |
| sum(range(5)) |
| reduce(lambda x,y: x+y,range(5)) |
| |
| |
| reduce(lambda x,y: x*y,range(1,6)) |
| def add(x, y =5): |
| return x + y |
| newadd = partial(add,4) |
| newadd() |
| add(4) |
- lru_cache
- 内部使用了一个字典
- key是由_make_key函数构造出来
| from functools import _make_key |
| print(_make_key((4, 5), {}, False)) |
| print(_make_key((4, 5), {}, True)) |
| print(_make_key((4,), {'y':5}, False)) |
| print(_make_key((), {'x':4, 'y':5}, False)) |
| print(_make_key((), {'y':5, 'x':4}, False)) |
应用
| @lru_cache |
| def fib(n): |
| return 1 if n < 3 else fib(n-1) + fib(n-2) |
| print(fib(500)) |
总结
lru_cache
装饰器应用
- 使用前提
- 同样的函数参数一定得到同样的结果,至少是一段时间内,同样输入得到同样的结果;
- 计算代价高,函数执行时间长
- 需要多次执行,每一次计算代价高
- 本质是建立函数调用的参数到返回值的映射
- 缺点
- 不支持缓存过期,key无法过期、失效
- 不支持清除操作
- 不支持分布式,是一个单机的缓存
lru_cache
适用场景,单机上需要空间换时间的地方,可以用缓存来将计算成快速的查询;