• Python的函数式编程: map, reduce, sorted, filter, lambda


    Python的函数式编程

    摘录:

    Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

    函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。

    而函数式编程(请注意多了一个“式”字)——Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。

    我们首先要搞明白计算机(Computer)和计算(Compute)的概念。

    在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。

    而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。

    对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。

    函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。

    函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

    Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

    目录

    • map 
    • reduce
    • sorted
    • filter
    • lambda表达式

    高阶函数

    Python变量可以指向函数

    >>> f = abs
    >>> f
    <built-in function abs>

    ⚠️函数名也是变量,所有不要在写代码时占用这个名字。

    传入函数

    因为变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

    把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。

    内建函数

    map

    map(function,Iterable)。 它接收2个参数:一个函数,一个Iterable,map把函数作用到Iterable上的每个元素上,返回一个新的Iterator。

    >>>list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
    ['1', '2', '3', '4', '5', '6', '7', '8', '9']

    ⚠️:

    • 类似Ruby的map方法,功能一样。ruby的Array#map,直接返回的是aray。
    • 而python的map返回的是一个<map object>。它可以被for循环调用,因此是可迭代对象iterable, 但也是iterator。

    ⚠️: list()是内建函数, class list([iteralble]), 本质是一个可变序列类型。

    附加:class list[(iterable)]

    • 用一对方括号表示空list:  []
    • 内部的项items,用逗号分开
    • 使用列表生成式: [x for in iterable] ,可创建一个列表。
    • 使用type constructor: list()或者 list(iterable) ,   可创建一个列表。
    >>> list('abc')
    ['a', 'b', 'c']
    >>> list( (1,2,3) )    #如果iterable已经是一个列表/tuple, 将创建并返回其副本。
    [1, 2, 3]
    >>>

    functools#reduce 

    reduce(函数,list) ,  传入的函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。

    练习:

    利用map()函数,把不规则输入,转化为首字母大写的名字。

    def normalize(name):
        b = str.lower(name[1:])
        
        a = str.upper(name[0])
        name = a + b
        return name
    
    L1 = ['adam', 'LISA', 'barT']
    L2 = list(map(normalize, L1))
    print(L2)
    #输出:
    ['Adam', 'Lisa', 'Bart']

    上面用到str.lower() ,str.upper()。

    "".join()可以把Iterator,list连接成为一个str。

    其实用str.title()语法糖即可。

    Python提供的sum()函数可以接受一个list并求和,请编写一个prod()函数,可以接受一个list并利用reduce()求积:

    from functools import reduce
    
    def prod(L):
        def 乘法(x , y):
            return x*y
        return reduce(乘法, L)
    
    print('3 * 5 * 7 * 9 =', prod([3, 5, 7, 9]))
    if prod([3, 5, 7, 9]) == 945:
        print('测试成功!')
    else:
        print('测试失败!')
    
    #输出
    3 * 5 * 7 * 9 = 945
    测试成功!

    Python支持中文变量。

    问题:def是否有作用域?

    Python和Ruby这点不一样。

    Ruby的def,class,module关键字,代表一个封闭的作用域,任何变量,必须作为参数传入def,才能使用。

    Python的def/class,不是封闭的作用域, ,它被执行时,可以读取定义时的外部变量。当然在它内部声明的变量,是局部的,不会影响外部。

    Python的def关键字和javascript的函数定义是一样的,非完全封闭的。

    sorted函数

    sorted(iterable, *, key=None, reverse = False)

    根据iterable中的items返回一个新的sorted list。

    关键字参数key=None,key是一个带单个参数的函数,用于自定义排序。

    这个函数作用于每个iterable的item上,并返回相应的结果,然后对结果排序, 最后sorted返回对应key的排序的iterable的排序。

    >>> sorted([36, 5, -12, 9, -21], key=abs)
    [5, 9, -12, -21, 36] 
    1. 逐一把iterable的items,传入key指向的函数abs。⚠️abs会运行n次,n等于iterable的项的数量。
    2. 得到keys = [36, 5, 12, 9, 21]
    3. 对上面keys的items进行排序            : [5, 9, 12,   21, 36]
    4. 最终返回的是对应上面排序的原items: [5, 9, -12, -21, 36]

    还可以对str进行比较,原理是根据字符的ASCII的大小比较。 因为ASCII中'Z' < 'a',所以排序的时候要忽略大小写。

    >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key= str.lower)
    ['about', 'bob', 'Credit', 'Zoo']

    ⚠️key指向的函数可以是任何函数,包括自定义的函数。

    filter函数

    filter(function, iterable)

    用function来筛选iterable中的items,根据返回值是True或False来决定是否保留item,构建一个新的iterator。

    #类似<filter object at 0x103f1bdf0>

    iterable可以是序列,支持迭代的容器, iterator。

    filter相当于一个生成器表达式。

    (item for item in iterable if function(item))

    例子:

    def not_empty(s):
        return s and s.strip()
    
    list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))
    # 结果: ['A', 'B', 'C'] 

    ⚠️:因为在Python,"", None,都代表False。这点和Ruby不同,Ruby中只有nil,false代表false。

    >>> bool("")
    False
    >>> bool(None)
    False

    例子:用filter求素数(深入理解generator)

    lambda表达式

    Python的lambda是一个轻量化的函数定义。Python对它定义了一些简单的功能。

    因为使用时无需定义一个名字,所以可以看做是python中的匿名函数

    lambda 参数,.. :  主体

    lambda相当于def关键字。返回的是主体计算后的结果。

    >>> (lambda x: x + 1)(2)
    3

    因为是表达式,所以也可以给它命名,即给一个变量指向它。

    lambda也接收多个参数,例子:

    >>> full_name = lambda first, last: f'Full name: {first} {last}'
    >>> full_name("hah","ww")

    ⚠️: f" {} "的写法。

    如果没有用变量命名,也可以调用:

    >>> lambda x, y: x + y
    <function <lambda> at 0x101665dc0>
    >>> _(1, 2)
    3

      

    从上面的了解可知,Python的lambda好像就是定义一个函数的语法糖。这不像其他语言的lambda。

    但需要⚠️的是,lambda就是lambda。它的使用有限制。

    语法规则:

    • 主体body内只能包括表达式,不能声明变量。
    • 只有一行。
    • 不支持注释
    • 可以被立即调用IIFE: ()()

    以上摘录自:https://realpython.com/python-lambda/

    更多内容没有看完。


    函数装饰器Decorator

    函数

    • 是对象。
    • 可以被赋值给变量。因此可通过变量调用函数。
    • 变量._name_:  拿到函数的名字。

    ⚠️dir(对象)可以拿到一个对象可用的方法。

    decorator返回值为另一个函数的函数,通常使用@wrapper语法形式来进行函数变换。常见例子classmethod(), staticmethod()。

    装饰器语法只是一种语法糖。可以嵌套使用:

    @f1(arg)
    @f2
    def func(): pass
    
    #等价于
    def func(): pass
    func = f1(arg)(f2(func))

    这是Python2.4版本的增加功能

    用于增为已经定义的函数/方法增加一些新的功能。装饰器,类似于包装。

    在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator可以用函数实现,也可以用类实现。

    decorator的简单例子

    给now方法加上装饰器log方法。就相当于now = log(now), 即把now函数当成log的参数,now函数的名字__name__重新指向log返回的结果:一个新的函数wrapper。

    因此执行方法now,now(),就相当于执行wrapper函数。

    def log(func):
        def wrapper(*args, **kw):
            print('call %s()' % func.__name__)
            return func(*args, **kw)
        return wrapper
    
    @log
    def now():
        print("2019")
    
    # now = log(now)
    now()

    这个例子,让decorator函数本身接收外面的作用域的变量:

    1. 首先, 代码会执行log('execute')返回一个decorator函数,并携带作用域中的字符串'execute';
    2. 然后, 执行decorator(now), 函数now作为参数,  返回wrapper函数本身,它携带字符串'execute'和now函数
    3. 当执行now()时,就是执行wrapper()。
    # 如果decorator本身需要传入参数, 那么编写一个返回decorator的高阶函数-------------------
    # 比如自定义log的文本:
    def log(text):
        def decorator(func):
            def wrapper(*args, **kw):
                print('%s %s()' %(text, func.__name__))
                return func(*args, **kw)
            # wrapper.__name__ = func.__name__
            return wrapper
        return decorator
    
    @log('execute') #首先, 返回一个decorator函数,并携带外面的作用域中的字符串'execute';然后, decorator接收函数now作为参数,最后返回函数wrapper
    def now():
        print("2019")
    
    now()
    print(now.__name__)  # 输出的是 wrapper。因为返回的函数wrapper()的名字就是'wrapper'。
    
    #为了防止有些依赖函数签名的代码执行冲突。加上:wrapper.__name__ = func.__name__
    
    # 可以import functools,然后@functools.wraps(func),代替上面的代码。

    Pthon的内建函数classmethod()就是一个装饰器函数。

    偏函数

    https://docs.python.org/zh-cn/3/library/functools.html#module-functools

  • 相关阅读:
    js splice 属性实现数组的删除,插入,替换
    js var多等式变量的定义
    SQL Server 收缩数据库
    sql2005 全文索引
    显示器分辨率推荐
    使用javascript打开链接的多种方法
    运算优先级
    jqGrid
    asp.net IE 页面刷新固定位置
    Left Join ,On Where
  • 原文地址:https://www.cnblogs.com/chentianwei/p/11792665.html
Copyright © 2020-2023  润新知