Python 进阶_函数式编程

目录

  • 目录
  • 函数式编程
  • Python 函数式编程的特点
  • 高阶函数
  • 匿名函数 lambda
  • 函数式编程相关的内置函数
    • filter 序列对象过滤器
    • map
    • reduce 折叠
    • 自定义的排序函数
  • 最后

函数式编程

首先要确定一点就是:函数 != 函数式,函数式编程是一种编程的范式。
特点:

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

Python 函数式编程的特点

需要注意的是,Python 不是也不可能会成为一种纯函数是编程语言,但 Python 仍支持许多有价值的函数式编程语言的构建方法。

  • Python 不是纯函数是编程,因为 Python 支持变量
  • Python 支持高阶函数,而且函数也可以作为变量传入
  • Python 支持闭包,可以返回一个函数

高阶函数

首先要明确一点,函数是由变量来引用的,这也是一个 Python 的特性:将对象引用和对象分离。
EG:

In [1]: abs(-1)
Out[1]: 1

In [2]: f = abs # 将函数名赋值给一个变量,让变量获得函数的引用

In [3]: f(-1)
Out[3]: 1

In [5]: abs = len

In [6]: abs([1, 2, 3])
Out[6]: 3

高阶函数: 能够接收函数作为一个参数的函数,就是高阶函数。
下面定义一个高阶函数:

In [1]: def add(x, y, f):
   ...:     return f(x) + f(y)
   ...:

In [2]: add(-1, -10, abs)
Out[2]: 11

函数 add 接收内建函数 abs 作为一个参数,所以 add 是一个高阶函数。

匿名函数 lambda

格式

lamba [arg1[, arg2, ...]]: expression # --> return: object of function

匿名函数,顾名思义就是没有名字的函数,可以忽略函数定义的函数。所以匿名函数的好处之一就是创建简易、方便,不需要以标准的定义方式(def)来创建。而且匿名函数可以如一般函数那样返回一个 callable 的函数对象,所以匿名函数一般会赋值给一个变量,或者直接作为一个函数实参来使用。从匿名函数的语法格式来看,其缺点也很明显,就是其函数体只能是一条 expression 而不能是一条关键字语句,如:print

NOTE: 因为匿名函数可以快速的返回一个函数对象,并且可以直接作为一个函数的实参使用,所以匿名函数经常被用于构建函数式的编程中。
EXAMPLE:

In [4]: def add(x, y):
   ...:     return x + y
   ...:

In [5]: lambda x, y: x + y
Out[5]: <function __main__.<lambda>> # 返回一个可调用的函数对象

In [6]: lam_add= lambda x, y: x + y

In [7]: lam_add(1, 2)
Out[7]: 3

上面两种方式的结果是一致的。

注意: 如果 lambda 返回的对象没有赋值给一个变量,那么这个函数对象的引用 == 0,会被垃圾回收掉。

函数式编程相关的内置函数

Python 提供了几个与函数式编程相关的内置函数,之所以说与函数式编程相关是因为这几个内置函数都需要接收一个函数对象作为参数,而这个函数对象通常由 lambda 来提供。

filter() 序列对象过滤器

让序列对象中的每一个元素都通过一个指定的过滤器,最终符合过滤条件(Return True)的元素会被返回为一个新的序列。
要自己实现一个 filter 函数,并不难。EG.

def filter(bool_func, seq):
    filtered_seq = []
    for index in seq:
        if bool_func(index):
            filtered_seq.append()
    return filtered_seq

EXAMPLE 1:求偶数

In [13]: filter(lambda x: x % 2 == 0, range(1,10))
Out[13]: [2, 4, 6, 8]

EXAMPLE 2:删除 None 或者空字符串

In [14]: def is_not_empty(s):
    ...:     return s and len(s.strip()) > 0
    ...:

In [15]: filter(is_not_empty, ['test', None, '', 'str', '  ', 'END'])
Out[15]: ['test', 'str', 'END']``

注意: 传入 filter 的函数最终的返回值一定是 True or False

map()

map 和 filter 很类似,但 map 函数通过把函数参数依次作用在 seq 的每个元素上,得到一个新的 seq 并返回。而且 map 的函数参数不要求一定要返回 True or False 。除此之外, map 还能处理多个序列参数。

def map(func, seq):
    maped_seq = []
    for index in seq:
        maped_seq.append(func(index))
    return maped_seq

EXAMPLE 1:处理单个序列对象

In [17]: map(lambda x :x+2, range(1,10))
Out[17]: [3, 4, 5, 6, 7, 8, 9, 10, 11]

EXAMPLE 2:处理多个序列对象

In [24]: map(lambda x, y :x + y, range(1,10), range(1,10))
Out[24]: [2, 4, 6, 8, 10, 12, 14, 16, 18]

注意:如果传递多个序列对象给 map 时,其处理的算法如下
1. 并行的将多个序列中 index 相同的元素获取,并捆绑到同一个元组中
2. 将这一个元组传递给函数参数中进行处理。
所以需要注意的是,两个序列的元素个数是否一致,函数参数是否能正确的处理这个元组对象

In [26]: map(None, range(1,6), range(1,6))
Out[26]: [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]

In [27]: zip(range(1,6), range(1,6))
Out[27]: [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]`

从这个例子可以看出 map 可以完成一个简单的 zip 功能,这是由其内部的实现算法决定的。

reduce() 折叠

reduce 需要传入一个 二元函数(具有两个形参的函数) 、一个序列对象和一个可选的 初始化器
其最常用的例子就是 累加

In [28]: reduce(add, range(1, 100))
Out[28]: 4950

In [35]: reduce(add, range(1, 100), 5000)
 # 初始化器 == 5000,即从 5000 开始累加
Out[35]: 9950

等效于:reduce(func, [1, 2, 3]) ⇒ func(func(1, 2), 3)

自定义的排序函数

Python 内置了一个排序函数 sorted

In [1]: sorted([36, 5, 12, 9, 21])
Out[1]: [5, 9, 12, 21, 36]

时 sorted 也是一个高阶函数,它可以接收一个比较函数来实现自定义排序。
比较函数的定义是:传入两个待比较的元素 x, y
1. 如果 x 应该排在 y 的前面,返回 -1
2. 如果 x 应该排在 y 的后面,返回 1
3. 如果 x 和 y 相等,返回 0

所以我们可以自定义一个比较函数,并且传递给 sorted 函数:

In [3]: def reversed_cmp(x, y):
   ...:     if x > y:
   ...:         return -1
   ...:     if x < y:
   ...:         return 1
   ...:     return 0
   ...:

In [4]: sorted([36, 5, 12, 9, 21], reversed_cmp)
   ...: [36, 21, 12, 9, 5]
   ...:
Out[4]: [36, 21, 12, 9, 5]

最后

本篇给出了一些内置高阶函数的例子,其实在编程中使用得更多的是自定义的高价函数,其中 闭包 就是一种非常常用的函数式编程。

时间: 2024-09-20 01:04:04

Python 进阶_函数式编程的相关文章

Python Decorator 和函数式编程

来源:https://www.oschina.net/translate/decorators-and-functional-python Python Decorator 和函数式编程 英文原文:Decorators and Functional Python Decorators 是Python中最重要的特性之一. 它除了使Python更好用外的, 它还能帮助我们以一种更有趣的方法考虑问题--函数式编程的方法 我会尝试着从零开始解释Decorator是怎么工作的. 首先, 我们会介绍一些帮助

Fn.py:享受Python中的函数式编程

尽管Python事实上并不是一门纯函数式编程语言,但它本身是一门多范型语言,并给了你足够的自由利用函数式编程的 便利.函数式风格有着各种理论与实际上的好处(你可以在Python的文档中找到这个列表): 形式上可证 模块性 组合性 易于调试及测试 虽然这份列表已经描述得够清楚了,但我还是很喜欢Michael O.Church在他的文章"函数式程序极少腐坏(Functional programs rarely rot)"中对函数式编程的优点所作的描述.我在PyCon UA 2012期间的讲

Python中的函数式编程

虽然人们总把Python当作过程化的,面向对象的语言,但是他实际上包含了函数化编程中,你需要的任何东西.这篇文章主要讨论函数化编程的一般概念,并说明用Python来函数化编程的技术. 我们最好从艰难的问题开始出发:"到底什么是函数化编程呢?"其中一个答案可能是这样的,函数化编程就是你在使用Lisp这样的语言时所做的(还有Scheme,Haskell,ML,OCAML,Mercury,Erlang和其他一些语言).这是一个保险的回答,但是它解释得并不清晰.不幸的是对于什么是函数化编程,很

Python 进阶_OOP 面向对象编程_组合与继承

#目录 前言 组合 派生 通过继承来覆盖重载方法 最常用的重载场景实例方法的重载 从标准类中派生类方法的重载 前言 我们定义一个类是希望能够把类当成模块来使用,并把类嵌入到我们的应用代码中,与其他的数据类型.逻辑执行流结合使用.一般来说我们可以使用两种方法在代码中利用类,那就是组合和派生. 组合 组合: 就是将不同的类混合并加入到其他类中,来 增加类的功能 / 提高代码的重用性 / 易于维护(对类的修改会直接反应到整个应用中) .我们可以实例化一个更大的对象,同时还可以添加一些实例属性和实例方法

Python 进阶_OOP 面向对象编程_实例属性和方法

目录 目录 构造器和解构器 构造器 __init__ 真构造器 __new__ 解构器 __del__ 实例方法 Python 中的 抽象方法 实例属性 查看实例属性 实例属性和类属性的区别 访问不可变类属性 访问可变类属性 构造器和解构器 构造器 __init__() 类函数 __init__() 是 Python 类中预定义的方法,需要被重载才会生效.以双下划线 "__" 开头和结尾, 在 Python 中使用这种命名方式的方法会被理解为是一种特殊方法, Python 的特殊方法功

Python 进阶_OOP 面向对象编程_类属性和方法

目录 目录 类属性 调用类属性 查看类属性 特殊的类属性 类方法 真构造器 __new__ 类属性 在理解类属性之前要先搞清楚 实例属性 和 函数属性 之间的区别: 1. 实例属性:指的是实例化类对象的属性,需要在类中使用 self 关键字来将其和实例化对象绑定的属性. 2. 函数属性:指的是定义在函数体内的属性,其可以是实例属性,也可以是类属性. 3. 类属性:是一个与实例无关的属性,比起实例属性而言,它更加的 静态,当定义在类方法中时,并不会因为方法调用的完毕而被回收.类属性,在类定义中直接

Python 进阶_OOP 面向对象编程_类和继承

目录 目录 类 最简单的类 类方法 构造器 __init__ 创建一个类 实例化一个对象 调用实例的方法和属性 创建子类 使用 super 来调用父类的构造器 实例化子类对象 调用子类的属性和方法 类属性方法的命名规则 类 类是实例的抽象, 实例是类的具体化. Python 中的类分为 经典类 和 新式类. 前者现在已经很少用到了, 其特点就是可以不需要继承任何父类:后者则刚好相反, 形式类必须至少有一个父类, 如果没有特定的父类需要继承时, 至少需要继承基类 object, 在后面给出例子.

Python 进阶_OOP 面向对象编程_静态方法和类方法

目录 目录 静态方法 类方法 使用函数修饰符来声明静态方法和类方法 静态方法 静态方法仅是类中的函数, 不需要绑定实例, 也就是说静态方法的定义不需要传入 self 参数. 静态方法不属于类的某一个实例对象, 而是属于类本身, 所以不需要绑定到实例对象. 可以通过 className.staticMethodName 的方式来调用. 特点: 只能使用静态变量, 所以始终占用同一个内存, 执行效率更高, 但不会被自动回收. 应用场景: 用于处理一些不会经常改变, 但却会被频繁调用的数据. EG:

Python 进阶_模块 &amp;amp; 包

目录 目录 模块的搜索路径和路径搜索 搜索路径 命名空间和变量作用域的比较 变量名的查找覆盖 导入模块 import 语句 from-import 语句 扩展的 import 语句 as 自动载入模块 模块导入的特性 模块内建函数 __import__ globals locals reload Package 包 __init__py import package 模块的搜索路径和路径搜索 搜索路径 默认的模块搜索路径在 Python 解析器编译安装时被指定, 我们可以通过 sys 模块来查看