美文网首页大数据 爬虫Python AI Sqlpython入门基础学习
他6年赚的钱已超过老爸一生的积蓄,谁说python阶级已固化?

他6年赚的钱已超过老爸一生的积蓄,谁说python阶级已固化?

作者: 编程新视野 | 来源:发表于2018-07-31 15:03 被阅读5次

    Python 函数式编程入门教程

    函数式编程源自于数学理论,它似乎也更适用于数学计算相关的场景,因此本文以一个简单的数据处理问题为例,逐步介绍 Python 函数式编程从入门到走火入魔的过程。

    一、什么是函数式编程?

    函数:function
    函数式:functional,是一种编程范式

    二、函数式编程的特点:

    1)把计算视为函数而非指令
    2)纯函数式编程:不需要变量,没有副作用,测试简单
    3)支持高阶函数,代码简洁

    三、Python支持的函数式编程

    1)Python不是纯函数式编程:允许有变量
    2)Python支持高阶函数:函数也可以作为变量传入
    3)Python支持闭包:有了闭包就能返回函数
    4)有限度的支持你匿名函数

    问题:计算 N 位同学在某份试卷的 M 道选择题上的得分(每道题目的分值不同)。

    首先来生成一组用于计算的伪造数据:


    四、入门

    首先来看常规的面向过程编程风格,我们需要遍历每个学生,然后遍历每个学生对每道题目的答案并与真实答案进行比较,然后将正确答案的分数累计:

    如果你觉得上面的代码非常直观且合乎逻辑,那说明你已经习惯按照计算机的思维模式进行思考了。通过创建嵌套两个 for 循环来遍历所有题目答案的判断和评分,这完全是为计算机服务的思路,虽然说 Python 中的 for 循环已经比 C 语言更进了一步,通常不需要额外的状态变量来记录当前循环的次数,但有时候也不得不使用状态变量,如上例中第二个循环中比较两个列表的元素。函数式编程的一大特点就是尽量抛弃这种明显循环遍历的做法,而是把注意集中在解决问题本身,一如在现实中我们批改试卷时,只需要将两组答案并列进行比较即可:



    然后再将所有正确题目的分数累加起来,即可:

    from functools import reduce
    
    reduced = reduce(lambda x, y: x + y[1][1], filtered, 0)
    print(reduced)
    
    

    以上是对一位学生的结果处理,接下来只需要对所有学生进行同样的处理即可:

    上面的示例通过 zip/filter/reduce/map 等函数将数据处理的方法打包应用到数据上,实现了基本的函数式编程操作。但是如果你对函数式有更深入的了解,你就会发现上面的 cal 方法中使用了全局变量 QUIZE,这会导致在相同输入的条件下,函数可能产生不同的输出,这是 FP 的大忌,因此需要进行整改:


    如此借助闭包(Closure)的方法,就可以维持纯净的 FP 模式啦!

    函数式编程的一大优势就是Immutable Data(数据不可变),就是不依赖于外部的数据,而且也不改变外部数据的值,这种思想可以大大减少我们代码的Bug,而且函数式编程也支持我们像使用变量一样使用函数。Python作为面向对象语言,也提供了对于函数式编程的支持,虽然并不是那么纯粹,而且也不支持尾递归优化。

    1.lambda的使用

    lambda即匿名函数,合理地使用lambda不仅可以减少我们的代码量,而且也可以更好地描绘代码逻辑,比如现在我们有下面这样一个函数。

    >>>deff(x):
    
    ...returnx+x
    
    # 调用这个函数
    >>>f(2)
    
    4
    这个函数如果我们用lamda改写的话,只要一行代码就够了。# lambda后面的x表示lambda函数要接收的参数,x + x表示lambda函数所要返回的值
    
    >>>f=lambdax:x+x
    
    # 可以看到f现在也是一个函数对象
    
    >>>f
    
    >
    
    # 调用lambda函数
    >>>f(2)
    
    4
    
    python中map()函数

    map(function, iterable)接收两个参数,第一个参数代表的是接收一个函数,第二个参数代表的是接收一个iteralbe类型的对象,比如list。

    map函数的原理是:

    1.每次从iterable中取出一个参数
    2.将这个参数传递给我们的函数
    3.然后函数返回的值加入一个list(这种说法不准确,只是为了帮助大家理解,后面我会解释)。等所有的iterable对象遍历完,map就把这个list返回给我们的调用者。下面我们直接通过实例来了解一下map的用法。

    python中reduce()函数

    reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。

    例如:
    请利用recude()来求积:
    输入:[2, 4, 5, 7, 12]
    输出:245712的结果

    def prod(x, y):
           return x*y
    print reduce(prod, [2, 4, 5, 7, 12])
    输出:3360
    
    python中filter()函数

    和map/reduce类似,filter(function, iterable)一次也接收两个参数,一个参数是函数,另外一个参数是iterable对象,从名字也可以看出,filter用于过滤iterble对象,比如说list(列表)。

    它的原理是每次从iterable对象中取出一个元素作用于我们的function,如果function返回True就保留该元素,如果返回False就删除该元素。下面我们通过一个实例来看一下filter的用法。

    定义一个函数,如果接收的字符s为空,那么返回False,如果为非空,那么返回True

    >>>function=lambdas:sands.strip()
    >>>iterable=['AJ',' ','Stussy','','CLOT','FCB',None]
    
    >>>filter(function,iterable)
    >>>list(filter(function,iterable))
    
    ['AJ','Stussy','CLOT','FCB']
    
    
    python中自定义排序函数

    Python内置的 sorted()函数可对list进行排序:

    sorted([36, 5, 12, 9, 21])
    输出:[5, 9, 12, 21, 36]
    

    但 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。
    因此,如果我们要实现倒序排序,只需要编写一个reversed_cmp函数:

    def reversed_cmp(x, y):
            if x > y:
                return -1
            if x < y:
                return 1
            return 0
    

    这样,调用 sorted() 并传入 reversed_cmp 就可以实现倒序排序:

    sorted([36, 5, 12, 9, 21], reversed_cmp)
    输出:[36, 21, 12, 9, 5]
    

    sorted()也可以对字符串进行排序,字符串默认按照ASCII大小来比较:

    sorted(['bob', 'about', 'Zoo', 'Credit'])
    输出:['Credit', 'Zoo', 'about', 'bob']
    

    'Zoo'排在'about'之前是因为'Z'的ASCII码比'a'小。

    示例:
    对字符串排序时,有时候忽略大小写排序更符合习惯。请利用sorted()高阶函数,实现忽略大小写排序的算法。
    输入:['bob', 'about', 'Zoo', 'Credit']
    输出:['about', 'bob', 'Credit', 'Zoo']

    走火入魔

    走火(fn.py)

    也许看了上面的 FP 写法,你还是觉得挺啰嗦的,并没有达到你想象中的结果,这时候就需要呈上一款语法糖利器:fn.pyfn.py 封装了一些常用的 FP 函数及语法糖,可以大大简化你的代码!

    pip install fn
    
    

    首先从刚刚的闭包开始,我们可以用更加 FP 的方法来解决这一问题,称为柯里化,简单来说就是允许接受多个参数的函数可以分次执行,每次只接受一个参数

    应用到上面的 cal 方法中:

    在 FP 中数据通常被看作是一段数据流在一串函数的管道中传递,因此上面的reduce和filter其实可以合并:

    reduce(lambda x, y: x + y[1][1], filter(lambda x: x[0] == x[1][0], zip(student.ans, quize)), 0)
    

    虽然更简略了,但是这样会大大降低代码的可读性(这也是 FP 容易遭受批评的一点),为此 fn 提供了更高级的函数操作工具:

    入魔(Hy)

    如果你觉得上面的代码已经足够魔性到看起来不像是 Python 语言了,然而一旦接受了这样的语法设定感觉也还挺不错的。如果你兴冲冲地拿去给 Lisp 或 Haskell 程序员看,则一定会被无情地鄙视,于是你痛定思痛下定决心继续挖掘 Python 函数式编程的奥妙,那么恭喜你,组织欢迎你的加入:Hail Hydra!

    哦不对,说漏了,是Hi Hy!


    Hy 是基于 Python 的 Lisp 方言,可以与 Python 代码进行完美互嵌(如果你更偏好 PyPy,同样也有类似的Pixie),
    除此之外你也可以把它当做一门独立的语言来看待,它有自己的解释器,可以当做独立的脚本语言来使用:

    pip install git+https://github.com/hylang/hy.git
    
    首先来看一下它的基本用法,和 Python 一样,安装完之后可以通过 hy 命令进入 REPL 环境:

    或者当做命令行脚本运行:

    #! /usr/bin/env hy
    (print "I was going to code in Python syntax, but then I got Hy.")
    

    保存为 awesome.hy:

    chmod +x awesome.hy
    ./awesome.hy
    

    接下来继续以上面的问题为例,首先可以直接从 Python 代码中导入:

    如果觉得不放心,还可以直接调用最开始定义的方法将结果进行比较:

    ;; 假设最上面的 normal 方法保存在 fun.py 文件中
    (import fun)
    (.normal fun students quize)
    

    还有很多包括视频我就不一一截图了,需要这些资料的可以先关注小编,转发评论,私信小编回复006、008即可领取资料。诚信小编!!!

    相关文章

      网友评论

      本文标题:他6年赚的钱已超过老爸一生的积蓄,谁说python阶级已固化?

      本文链接:https://www.haomeiwen.com/subject/cpxhvftx.html