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的信息。中间通过反射进行取值和赋值的操作。

 

posted @ 2018-05-08 16:04  wanstack  阅读(263)  评论(0编辑  收藏  举报