匿名函数

特点:
    定义函数时不需要定义函数名
实现:
    借助 lambda 关键字
    lambda parameter_list: expression
    注意:expression只能包含表达式!不能包含语句!

示例:
    一般函数:
        def add(x, y):
        return x + y
    上述add函数的匿名形式:(匿名函数 或 叫做Lambda表达式)
        lambda x,y: x+y


匿名函数的调用:
    因为没有名字,所以需要赋值给变量,然后调用
    f = lambda x,y: x+y
    print(f(1,2)) #输出 3

三元表达式

地位:
    表达式版本的if else 语句
实现:
    Java的形式  x > y ? 1 : 1
    Python的三元表达式
    [条件为真时返回的结果] if [条件判断] else [条件为假时的返回结果]
示例:
    x = 1
    y = 2
    print( True if x > y else False) #输出 False

class map(func,*iterables)

使用场景
    对序列中的全部元素执行相同的操作
应用:
    求列表中每个数字的平方
示例:
    list_x = [1,2,3,4,5,6]

    def func(x):
        return x * x
    print(map(func, list_x))    
    #输出 <map object at 0x0000000000A5D7F0>

    print(list(map(func, list_x)))  
    #输出 [1, 4, 9, 16, 25, 36]
注意:
    map会吧集合中的每个元素都传入到第一个参数,func中去
    即按照一定的规则,对一族元素进行映射,规则就是func中的逻辑

map+lambda:
注意:
    map(func,*iterables)结合Lambda表达式
    直接替换掉参数func
    注意第二个参数 *iterables,带星号,表示可变参数
    如果func参数有多个,第二个参数位置可以传入多个list
示例:
    完成返回平方的功能:
    print( list( map( lambda x: x*x, [1,2,3,4,5] ) ) )
    #输出 [1, 4, 9, 16, 25]

    Lambda表达式有两个参数
    print( list( map( lambda x,y: x*y, [1,2,3,4,5],[1,2,3,4,5] ) ) )
    #输出[1, 4, 9, 16, 25]

    注意多个参数时会一一对照,多余会丢弃
    print( list( map( lambda x,y: x*y, [1,2,3,4,5],[1] ) ) )
    #输出[1]
    上述输出只有一个元素,因为输入的两个参数只有第一个元素满足运行条件

def reduce

注意:
    map类在全局命名空间,不需要引入模块,reduce函数需要引入functools
    def reduce(function,sequence,initial=None)
示例:
    from functools import reduce
    list_x = [1,2,3,4]    
    #完成求和
    print( reduce( lambda x,y:x+y, list_x ) )
    #输出 10 运算过程:
    #1   2   3   4 ...
    #    3   3   4 ...
    #        6   4 ...
    #            10...

应用场景:
    连续规约计算,从前向后对数据进行两两规约计算

带initial参数:
    print( reduce( lambda x,y:x+y, list_x, 10 ) )
    #输出 10 运算过程:
    #10  1   2   3   4 ...
    #    11  2   3   4 ...
    #        13  3   4 ...
    #            16  4 ...
    #                20

扩展:
    map/reduce 映射+规约,进行并行计算(大数据处理)

class filter(func or None, iterables)

注意:
    由参数可知,只能对一个序列进行处理,参数func仍然可以被Lambda表达式替换
    另:第一个参数必须可以返回True/False 或者代表True/False的值
    filter依靠TF来判断是否要剔除,返回false表示保留
示例:
    print( filter( lambda x:False if x == 0 else True, [0,0,1,2,3,0] ))
    #输出 <filter object at 0x000000000111D828>

    print( list( filter( lambda x:False if x == 0 else True, [0,0,1,2,3,0] )))
    #输出 [1, 2, 3]

对比:
    命令式编程:依靠def,if else,for/while等等

    函数式编程:依靠map,reduce,filter + Lambda(三大函数 + 算子)
    解释:
        map,reduce近似循环
        filter近似判断
        Lambda近似函数
    上述集合使用,可以完成流程控制
注意:
    Python只是支持部分函数式编程的特性,本身并不是函数式编程语言

装饰器

地位:
    非常有用、常用,是一种设计模式,类似Java的注解
示例:
    对所有函数追加打印当前时间的功能
代码:
    import time
    def func1():
        print(time.time())
        #输出 1509550613.9346058 Unix时间戳
        print('This is a function')
    func1()
追加修改原则:
    开闭原则:对修改是封闭的,对扩展是开放的,如果需要打印时间,会迫使修改函数内部


进一步:
    使用函数式编程思想的封装,没有违反开闭原则
    def func2():
        print('This is a function')         
    def print_time(func):
        print(time.time())  
        func()
    print_time(func2)
    上述缺点:打印时间并没有和原函数绑定

再进一步:
    使用装饰器完成上述功能
    装饰器的基本结构:
        def decorator():
            def wrapper():
                pass#装饰器的逻辑
            return wrapper
    示例:
        import time
        def func1():
            print('This is a function')
        #构造装饰器
        def decorator(func):
            def wrapper():
                print(time.time())
                func()
            return wrapper

        decorator(func1)() 完成调用
    解释:
        真正业务逻辑在wrapper内
    缺点:
        仍然没有将打印时间和原始函数绑定起来

再进一步:
    使用装饰器语法糖,使用@符号
    代码:
        import time

        #构造装饰器
        def decorator(func):
            def wrapper():
                print(time.time())
                func()
            return wrapper
        @decorator
        def func1():
            print('This is a function')
        func1() #完成调用,而且没有改变原有调用逻辑
评价:
    这才是完整的有意义的装饰器的使用方法,只需要在原有函数定义上添加
    @decorator就会执行附加操作,体现了AOP面向切面编程

对带参数的原函数添加装饰器

示例:
    import time

    #构造装饰器
    def decorator(funcname):
        def wrapper(*fc): 
        #此处的参数,应该和被修饰函数的参数个数相对于,
        #但是为了通用性,应该使用*params可变参数形式
            print(time.time())
            funcname(*fc)
        return wrapper

    @decorator 
    def func1(f_param):
        print('This is ',f_param)

    @decorator 
    def func2(param1,param2):
        print('This is ',param1,param2)

    func1('Tom')
    func2('Tom','Jack')
    上述成功完成了对不同参数的函数进行添加装饰器

进一步优化
适应关键字参数:
    import time

    #构造装饰器
    def decorator(funcname):
        def wrapper(*fc,**kw): #参数**kw适用于关键字参数
            print(time.time())
            funcname(*fc,**kw)
        return wrapper

    @decorator
    def func2(param1,**param2):
        print('This is ',param1,param2)
    func2('Tom',a = '1',b = '2') #正确适应了关键字参数的函数

关键字参数,回顾:

    对于含有关键字参数的函数 
        def func2(param1,**param2):
            print('This is ',param1,param2)
        func2('Tom',a = '1',b = '2')
        输出 This is  Tom {'b': '2', 'a': '1'}

综上:
    此时的装饰器:
    def decorator(funcname):
        def wrapper(*fc,**kw):  
            print(time.time())
            funcname(*fc,**kw)
        return wrapper
    在待装饰函数具有多个可变参数,或者包含关键字参数的情况均可使用


装饰器小结:
    装饰器的思想:对封装的单元追加行为,保证原有单元的稳定性,
    不破坏单元内的代码,遵循开闭原则,更加体现了装饰器内代码的复用

应用场景:
    flask内,添加@api.route可以使函数变为控制器
        @api.route('/get',methods=['GET'])
        def test_http():
            p = request.agrs.get('name')
            return p,200

    添加多个装饰器,追加不同的操作
        @api.route('/get',methods=['GET'])
        @auth.login_required
        def get_money():
            p = request.agrs.get('psw')
            r = generate_hash(p)
            return 'user',200