zoukankan      html  css  js  c++  java
  • Python 函数式编程 闭包

    AstralWind 的博客上有对函数式编程很好地讲解,一下做一些节选

    1.1. 什么是函数式编程?
    函数式编程使用一系列的函数解决问题。函数仅接受输入并产生输出,不包含任何能影响产生输出的内部状态。任何情况下,使用相同的参数调用函数始终能产生同样的结果。

      在一个函数式的程序中,输入的数据“流过”一系列的函数,每一个函数根据它的输入产生输出。函数式风格避免编写有“边界效应”(side effects)的函数:修改内部状态,或者是其他无法反应在输出上的变化。完全没有边界效应的函数被称为“纯函数式的”(purely functional)。避免边界效应意味着不使用在程序运行时可变的数据结构,输出只依赖于输入。

      可以认为函数式编程刚好站在了面向对象编程的对立面。对象通常包含内部状态(字段),和许多能修改这些状态的函数,程序则由不断修改状态构成;函数式编程则极力避免状态改动,并通过在函数间传递数据流进行工作。但这并不是说无法同时使用函数式编程和面向对象编程,事实上,复杂的系统一般会采用面向对象技术建模,但混合使用函数式风格还能让你额外享受函数式风格的优点。

    1.2. 为什么使用函数式编程?
    函数式的风格通常被认为有如下优点:

    • 逻辑可证
    • 模块化      函数式编程推崇简单原则,一个函数只做一件事情,将大的功能拆分成尽可能小的模块。小的函数更易于阅读和检查错误。
    • 组件化      小的函数更容易加以组合形成新的功能。
    • 易于调试   细化的、定义清晰的函数使得调试更加简单。当程序不正常运行时,每一个函数都是检查数据是否正确的接口,能更快速地排除没有问题的代码,定位到出现问题的地方。
    • 易于测试    不依赖于系统状态的函数无须在测试前构造测试桩,使得编写单元测试更加容易。
    • 更高的生产率   函数式编程产生的代码比其他技术更少(往往是其他技术的一半左右),并且更容易阅读和维护。

    1.3. 如何辨认函数式风格?
    支持函数式编程的语言通常具有如下特征,大量使用这些特征的代码即可被认为是函数式的:

    • 函数是一等公民   函数能作为参数传递,或者是作为返回值返回。
    • 匿名函数(lambda)  lambda表达式定义一个匿名的函数,如果这个函数仅在编码的位置使用到,你可以现场定义、直接使用:

      lst.sort(lambda o1, o2: o1.compareTo(o2))

    • 封装控制结构的内置模板函数 

    在Python里,过滤由一个名为filter的内置函数实现。有了这个函数,解释器就学会了如何“过滤”,而我们只需要把规则告诉它:
    lst2 = filter(lambda n: n > 0, lst)
    这个函数带来的好处不仅仅是少写了几行代码这么简单。
    封装控制结构后,代码中就只需要描述功能而不是做法,这样的代码更清晰,更可读。因为避开了控制结构的干扰,第二段代码显然能让你更容易了解它的意图。
    另外,因为避开了索引,使得代码中不太可能触发下标越界这种异常,除非你手动制造一个。
    函数式编程语言通常封装了数个类似“过滤”这样的常见动作作为模板函数。唯一的缺点是这些函数需要少量的学习成本,但这绝对不能掩盖使用它们带来的好处。

      部分内建函数介绍

        1.reduce(function, iterable[, initializer])

    1 def reduce_(function, lst, initial):
    2     result = initial
    3     for num in lst:
    4         result = function(result, num)
    5     return result

    它的第二个参数可以是任何可迭代的对象(实现了__iter__()方法的对象);
    如果不指定第三个参数,则第一次调用function将使用iterable的前两个元素作为参数。
    由reduce和一些常见的function组合成了下面列出来的内置函数:

    all(iterable) == reduce(lambda x, y: bool(x and y), iterable)
    any(iterable) == reduce(lambda x, y: bool(x or y), iterable)
    max(iterable[, args...][, key]) == reduce(lambda x, y: x if key(x) > key(y) else y, iterable_and_args)
    min(iterable[, args...][, key]) == reduce(lambda x, y: x if key(x) < key(y) else y, iterable_and_args)
    sum(iterable[, start]) == reduce(lambda x, y: x + y, iterable, start)

    2.map(function, iterable, ...)

    def map_(function, lst):
        result = []
        for item in lst:
            result.append(function(item))
        return result 

    map还可以接受多个iterable作为参数,在第n次调用function时,将使用iterable1[n], iterable2[n], ...作为参数。
    3.filter(function, iterable)
      这个函数的功能是过滤出iterable中所有以元素自身作为参数调用function时返回True或bool(返回值)为True的元素并以列表返回
    4.zip(iterable1, iterable2, ...)
      这个函数返回一个列表,每个元素都是一个元组,包含(iterable1[n], iterable2[n], ...)。
      例如:zip([1, 2], [3, 4]) --> [(1, 3), (2, 4)]
      如果参数的长度不一致,将在最短的序列结束时结束;如果不提供参数,将返回空列表。

    • 闭包(closure)

    闭包是绑定了外部作用域的变量(但不是全局变量)的函数。大部分情况下外部作用域指的是外部函数。
    闭包包含了自身函数体和所需外部函数中的“变量名的引用”。引用变量名意味着绑定的是变量名,而不是变量实际指向的对象;如果给变量重新赋值,闭包中能访问到的将是新的值。
    闭包使函数更加灵活和强大。即使程序运行至离开外部函数,如果闭包仍然可见,则被绑定的变量仍然有效;每次运行至外部函数,都会重新创建闭包,绑定的变量是不同的,不需要担心在旧的闭包中绑定的变量会被新的值覆盖。

    传送门:闭包详解 

  • 相关阅读:
    xsos:一个在Linux上阅读SOSReport的工具
    RHEL sosreport
    sosreport -a --report
    环境变量
    读研重要的是要明白你自己要干什么, 不能等导师来告诉你你应该干什么. 研究生的优势在于理论功底深厚, 思维具有穿透力,
    awk sed grep 常用命令
    如何删除文件中的空行
    Vim删除空行
    WPS 2010 页眉下方添加下划线
    Android开发环境搭建
  • 原文地址:https://www.cnblogs.com/tangr206/p/3056868.html
Copyright © 2011-2022 走看看