restframework api(基础1)
最近项目忙成狗,都没时间好好看看开发的东西了,正好最近开始看rest api的东西,真是个好东西啊。可以前后端分离,但是在学习的过程中,遇到各种问题。还是基础不够扎实。本次rest api的会一边遇坑一边补习之前的东西。
一 functools库
真是一个神奇的python库,以前一直没注意。
1 偏函数 partial
先找文档学习一下,最后看源码,源码能看懂就看,看不懂那就是真的看不懂了。
文档参考 https://blog.csdn.net/appleyk/article/details/77609114
partial 一共有三个部分:
(1)第一部分也就是第一个参数,是一个函数,这个函数可以是你定义的,也可以是Python内置函数
(2)第二部分是一个可变参数,*args,比如内置函数max的参数就是一个可变参数,max(1,2,3,4,5)=5
(3)第三部分是一个关键字参数,比如内置函数int的第二个参数就是命名关键字参数,默认base=10,表示int转换时默认是10进制的:
partial函数的作用就是:将所作用的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数的后续参数,原函数有关键字参数的一定要带上关键字,没有的话,按原有参数顺序进行补充。
使用一下吧
A、偏函数的第二个部分(可变参数),按原有函数的参数顺序进行补充,参数将作用在原函数上,最后偏函数返回一个新函数(类似于,装饰器decorator,对于函数进行二次包装,产生特殊效果;但又不同于装饰器,偏函数产生了一个新函数,而装饰器,可改变被装饰函数的函数入口地址也可以不影响原函数)
这里我的理解是:首先偏函数能做的事情,装饰器也能做,其次偏函数可以操作源函数的参数,可是装饰器可以操作函数的入口。那为啥还有偏函数,估计是因为比装饰器简单吧。用起来应该很爽。
案例:我们定义一个sum函数,参数为*args可变,计算这些可变参数的和。
扩展:我们想要对sum函数求和后的结果,再加上10加上20甚至加更多,得到一个新的结果。
实现:我们分别用decorator和partial来实现,对比一下二者的区别。
好激动,因为可以紧跟作者脚步可以复习一下装饰器的东西了。
(1)装饰器实现
基础:http://www.cnblogs.com/wanstack/p/9009932.html
# /usr/bin/env Python3 # -*- encoding:UTF-8 -*- from functools import wraps def sum_add(*args1): #我们要给我们的装饰器decorator,带上参数 def decorator(func): @wraps(func) #加上这句,原函数func被decorator作用后,函数性质不变 def my_sum(*args2): #注意,参数要和原函数保持一致,真正实行扩展功能的是外层的装饰器 my_s = 0 for n in args1: my_s = my_s +n #这个是我们新加的求和结果 return func(*args2) + my_s #这个,我们在原求和函数的结果上再加上s,并返回这个值 return my_sum #返回my_sum函数,该函数扩展原函数的功能 return decorator #返回我们的装饰器 @sum_add(10,20) #启用装饰器 对sum函数进行功能扩展 def sum(*args): s = 0 for n in args: s = s+n return s print(sum(1,2,3,4,5)) print(sum.__name__)
这里以前一直有一个疑问,今天突然间理解了,以前一直觉得为啥装饰器带上参数就需要写三层嵌套函数,因为@decorator没有()所以是不需要执行的,而加上参数@decorator(*args)是已经开始执行了啊。尼玛就是这么简单,当时困扰了好久。归根结底还是不理解。有时候想想做技术真的是理解了就是理解了,不理解死记硬背也不理解。
看看偏函数的实现:
# /usr/bin/env Python3 # -*- encoding:UTF-8 -*- from functools import partial def sum(*args): s = 0 for n in args: s = s + n return s sum_add_10 = partial(sum,10) #10 作用在sum第一个参数的位置 sum_add_10_20 = partial(sum,10,20) #10 20 分别作用在sum第一个和第二个参数的位置 print('A____________我们看下原函数sum的函数地址入口:') print(sum) print('B______我们看下partial函数返回函数的地址入口:') print(partial(sum,10)) print(sum_add_10(1,2,3,4,5)) # --> 10 + 1 + 2 + 3 + 4 + 5 = 25 print(sum_add_10_20(1,2,3,4,5)) # --> 10 + 20 + 1 + 2 + 3 + 4 + 5 = 45
一步到位,当然还有其他方式一步到位的写法。这里的partial(函数,函数的第一个参数位置) 这部就是可以对已经存在的函数的参数中,继续传递参数吗。
B、偏函数的第三个部分(关键字参数),按原有函数的关键字参数进行填补,参数将作用在原函数上,最后偏函数返回一个新函数
案例:我们定义一个mod求余函数,两个参数,一个是被除数,一个是除数,除数我们这里用命名关键字参数表示,默认值2
扩展:我们的除数不固定,可以是对2就行求余,也可以对3,对4,总之我们需要指定除数的值
返回结果: True 或 False
实现:原函数实现和partial函数实现
# /usr/bin/env Python3 # -*- encoding:UTF-8 -*- import functools def mod(m,*,key=2): return m % key == 0 mod_to_2 = functools.partial(mod,key=2) print('A__3___使用原函数的默认关键字参数对2进行求余:') print(mod(3)) #对2进行求余-- 原函数 使用默认参数 print('B__3___使用偏函数对2进行求余:') print(mod_to_2(3)) #对2进行求余-- 新函数 --偏函数产生 mod_to_5 = functools.partial(mod,key=5) print('C__25___使用原函数的关键字参数对5进行求余:') print(mod(25,key=5)) #对5进行求余 -- 原函数 print('D__25___使用偏函数对5进行求余:') print(mod_to_5(25)) #对5进行求余 -- 新函数--偏函数产生
2 wraps
其实上面已经用到了wraps,一般在使用装饰器的时候会使用这个,他也是一个装饰器,至于为什么会用他,因为我们在使用装饰器的时候,会损失一些基本信息,比如fun.__name__等等,用上他,就不会了。
啥也不说了,直接上代码。
# coding:utf-8 from functools import partial WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__', '__annotations__') WRAPPER_UPDATES = ('__dict__',) def update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): """Update a wrapper function to look like the wrapped function wrapper is the function to be updated wrapped is the original function assigned is a tuple naming the attributes assigned directly from the wrapped function to the wrapper function (defaults to functools.WRAPPER_ASSIGNMENTS) updated is a tuple naming the attributes of the wrapper that are updated with the corresponding attribute from the wrapped function (defaults to functools.WRAPPER_UPDATES) """ """ try: <语句> except <name>: <语句> #如果在try部份引发了名为'name'的异常,则执行这段代码 else: <语句> #如果没有异常发生,则执行这段代码 finally: print("不管有没有异常,我总是被执行了") """ print("wrapper==========" ,wrapper) # 这里的wrapper是一个inner函数 for attr in assigned: try: # 这里的wrapped应该是被装饰的函数,从wrapped中获取assigned的属性 value = getattr(wrapped, attr) print("value============",value) except AttributeError: pass else: # 这里try执行了,这里就把value的值赋值给wrapper对象 setattr(wrapper, attr, value) v = getattr(wrapper,attr) print('v------',v) for attr in updated: print("getattr(wrapper, attr)",getattr(wrapper, attr)) # 这是个字典 getattr(wrapper, attr).update(getattr(wrapped, attr, {})) # Issue #17482: set __wrapped__ last so we don't inadvertently copy it # from the wrapped function when updating __dict__ wrapper.__wrapped__ = wrapped # Return the wrapper so this can be used as a decorator via partial() return wrapper # 这个wrapper是一个inner def wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): """Decorator factory to apply update_wrapper() to a wrapper function Returns a decorator that invokes update_wrapper() with the decorated function as the wrapper argument and the arguments to wraps() as the remaining arguments. Default arguments are as for update_wrapper(). This is a convenience function to simplify applying partial() to update_wrapper(). """ # 其中update_wrapper是一个函数,wtrapped,assigned,updated是这个函数的关键字参数 # 这里执行update_wrapper函数,返回一个wrapper return partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) def decorator(func): """ 1. value = getattr(wrapped, attr) 从func中拿到一些属性信息 2. setattr(wrapper, attr, value) 把这些属性信息赋值给inner 3. return wrapper 返回inner :param func: :return: """ @wraps(func) # func = wraps(func) def inner(): print('起床先睁眼') func() return inner @decorator # func = decorator(func) def func(): print('早上起床') func() # 执行inner() print(func.__name__) print(func.__dict__)
可能看着有点乱,但是只要就是
1. value = getattr(wrapped, attr) 从func中拿到一些属性信息 2. setattr(wrapper, attr, value) 把这些属性信息赋值给inner 3. return wrapper 返回inner
做了这三件事情,当然了__dict__中的我没写,但是大概就是这么个流程,现在知道了即使,我们返回的是inner函数,也会对应的是func的信息。中间通过反射进行取值和赋值的操作。