文档章节

函数式编程之 Python

SEOwhywhy
 SEOwhywhy
发布于 2018/12/05 22:15
字数 1866
阅读 5
收藏 0

  1 函数式编程概述
  
  前提:函数在 Python 中是⼀等对象
  
  工具:built-in ⾼阶函数;lambda 函数;operator 模块;functools 模块
  
  模式:闭包与装饰器
  
  替代:⽤用 List Comprehension 可轻松替代 map 和 filter(reduce 替代起来⽐比较困难)
  
  原则:No Side Effect
  
  何为 No Side Effect? 函数的所有功能就仅仅是返回一个新的值而已,没有其他行为,尤其是不得修改外部变量。因⽽,各个独⽴的部分的执⾏顺序可以随意打乱,带来执⾏顺序上的⾃自使得⼀系列新的特性得以实现:⽆锁的并发;惰性求值;编译器器级别的性能优化等
  
  1.1 程序的状态与命令式编程
  
  程序的状态首先包含了当前定义的全部变量
  
  有了程序的状态,我们的程序才能不断往前推进
  
  命令式编程,就是通过不断修改变量的值,来保存当前运⾏的状态,来步步推进
  
  1.2 函数式编程
  
  通过函数来保存程序的状态(通过函数创建新的参数和返回值来保存状态)
  
  函数一层层的叠加起来,每个函数的参数或返回值代表了⼀个中间状态
  
  命令式编程⾥一次变量值的修改,在函数式编程⾥变成了⼀个函数的转换
  
  最自然的方式:递归
  
  2 一等函数
  
  一等对象的定义:
  
  在运⾏时创建
  
  能赋值给变量或数据结构中的元素
  
  能作为参数传给函数
  
  能作为函数的返回结果
  
  Python 中,所有函数的都是一等对象,简称为一等函数
  
  2.1 高阶函数
  
  定义:接受函数为参数,或把函数作为返回结果的函数
  
  2.1.1 map 映射
  
  map() 是 Python 内置的高阶函数,它接收一个函数 f 和一个可迭代对象,并通过把函数 f 依次作用在 可迭代对象 的每个元素上,并返回一个新的可迭代对象。
  
  def f(x):
  
  return x * x
  
  print('map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])):',
  
  list(map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])))
  
  show:
  
  map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])): [1, 4, 9, 16, 25, 36, 49, 64, 81]
  
  替代方案:
  
  [x*x for x in range(1,10)]
  
  def format_name(s):
  
  s1 = s[0:1].upper() + s[1:].lower()
  
  return s1
  
  print("map(format_name, ['adam', 'LISA', 'barT']):",
  
  list(map(format_name, www.mhylpt.com['adam', 'LISA', 'barT'])))
  
  map(format_name, ['adam', 'LISA', 'barT']): ['Adam', 'Lisa', 'Bart']
  
  替代方案:
  
  [format_name(name) for i, name in enumerate(['adam', 'LISA', 'barT'])]
  
  因而,列表推导可以很好的替换 map 函数。
  
  2.1.2 filter 过滤器
  
  x = [(), [], {}, None, '', False, 0, True, 1, 2, -3]
  
  x_result = filter(bool,www.michenggw.com x)
  
  list(x_result)
  
  [True, 1, 2, -3]
  
  替代方案:
  
  [i for i in x if bool(i)]
  
  print("filter((lambda x: x>0), range(-5, 5)):",
  
  list(filter((lambda x: x > 0), range(-5, 5))))
  
  filter((lambda x: x>0), range(-5, 5)): [1, 2, 3, 4]
  
  替代方案:
  
  [x for x in range(-5, 5) if x > 0]
  
  2.1.3 reduce 递推
  
  from functools import reduce
  
  m = 2
  
  n = 5
  
  reduce(lambda x, y: x * y, list(range(1, n + 1)), m)
  
  240
  
  def multiply(a, b):
  
  return a * b
  
  reduce(multiply, range(1, 5))
  
  24
  
  2.1.4 zip 并行
  
  print("zip( [1, 2, 3], [4, 5, 6]):", list(zip([1, 2, 3], [4, 5, 6])))
  
  show:
  
  zip( [1, 2, 3], [4, 5, 6]): [(1, 4), (2, 5), (3, 6)]
  
  2.1.5 sorted 排序
  
  >>> sorted([x * (-1) ** x for x in range(10)])
  
  [-9, -7, -5, -3, -1, 0, 2, 4, 6, 8]
  
  >>> sorted([x * (-1) ** x for x in range(10)], reverse=True)
  
  [8, 6, 4, 2, 0, -1, -3, -5, -7, -9]
  
  >>> sorted([x * (-1) ** x for x in range(10)], key=abs)
  
  [0, -1, 2, -3, 4, -5, 6, -7, 8, -9]
  
  >>> sorted([x * (-1) ** x for x in range(www.mingcheng178.com)], reverse=True, key=abs)
  
  [-9, 8, -7, 6, -5, 4, -3, 2, -1, 0]
  
  min 与 max 同理。
  
  2.2 partial
  
  functools 这货用于高阶函数:指那些作用于函数或者返回其他函数的函数。通常情况下,只要是可以被当做函数调用的对象就是这个模块的目标。
  
  假设有如下函数:
  
  def multiply(x, y):
  
  return x * y
  
  现在,我们想返回某个数的双倍,即:
  
  >>> multiply(3, y=2)
  
  6
  
  >>> multiply(4, y=2)
  
  8
  
  >>> multiply(5, y=2)
  
  10
  
  上面的调用有点繁琐,每次都要传入 y=2,我们想到可以定义一个新的函数,把 y=2 作为默认值,即:
  
  def double(x, y=2):
  
  return multiply(x, y)
  
  现在,我们可以这样调用了:
  
  >>> double(www.gcyl158.com)
  
  6
  
  >>> double(4)
  
  8
  
  >>> double(5)
  
  10
  
  事实上,我们可以不用自己定义 double,利用 partial,我们可以这样:
  
  from functools import partial
  
  double = partial(multiply, y=2)
  
  partial 接收函数 multiply 作为参数,固定 multiply 的参数 y=2,并返回一个新的函数给 double,这跟我们自己定义 double 函数的效果是一样的。
  
  所以,简单而言,partial 函数的功能就是:把一个函数的某些参数给固定住,返回一个新的函数。
  
  需要注意的是,我们上面是固定了 multiply 的关键字参数 y=2,如果直接使用:
  
  double = partial(multiply, 2)
  
  则 2 是赋给了 multiply 最左边的参数 x。
  
  from functools import partial
  
  def subtraction(x,www.gcyL157.com y):
  
  return x - y
  
  f = partial(subtraction, 4)  # 4 赋给了 x
  
  >>> f(10)   # 4 - 10
  
  -6
  
  组合高阶函数:
  
  from functools import partial
  
  abs_sorted = partial(sorted, key=abs)
  
  abs_sorted([x * (-1) ** x for x in range(10)])
  
  show:
  
  [0, -1, 2, -3, 4, -5, 6, -7, 8, -9]
  
  abs_reverse_sorted = partial(sorted, key=abs, reverse=True)
  
  abs_reverse_sorted([x * (-1) ** x for x in range(10)])
  
  show:
  
  [-9, 8, -7, 6, -5, 4, -3, 2, -1, 0]
  
  2.3 匿名函数
  
  定义:使⽤用 lambda 表达式创建的函数,函数本身没有名字
  
  特点:只能使⽤用纯表达式,不能赋值,不能使⽤用 while 和 try 等块语句
  
  语法: lambda [arg1 [,arg2 [,arg3]]]: expression
  
  Expressions get a value; Statements do something
  
  lambda & def
  
  写法上:
  
  def 可以用代码块,一个代码块包含多个语句
  
  lambda只能⽤单行表达式,⽽表达式仅仅是单个语句中的⼀种
  
  结果上:
  
  def 语句一定会增加⼀个函数名称
  
  lambda 不会,这就降低了了变量名污染的⻛险
  
  能用一个表达式直接放到 return 里返回的函数都可以⽤ lambda 速写
  
  def multiply(a, b):
  
  return a * b
  
  multiply_by_lambda = lambda x,y: x * y
  
  List + lambda 可以得到⾏为列表
  
  f_list = [lambda x: x + 1, lambda x: x ** 2, lambda x: x ** 3]
  
  [f_list[j](10) for j in range(3)]
  
  [11, 100, 1000]
  
  在 AI 领域里,这种写法常用于处理数据,比如按预定的⼀系列模式处理数据
  
  下面我们以两个例子来结束高阶函数:
  
  例1:
  
  L = range(6)
  
  # 计算l中每个元素的两倍和平方,并将两种组成一个列表
  
  # lambda表达式和python函数一样,也可以接受函数作为参数
  
  def twoTimes(x):
  
  return x * 2
  
  def square(x):
  
  return x**2
  
  print([list(map(lambda x: x(i), [twoTimes, square])) for i in L])
  
  print(list(filter(lambda x: x % 2 == 0, L)))
  
  # 内置reduce函数,计算 L 的和
  
  print(reduce(lambda accumValue, newValue: accumValue + newValue, L, 0))
  
  [[0, 0], [2, 1], [4, 4], [6, 9], [8, 16], [10, 25]]
  
  [0, 2, 4]
  
  15
  
  我们依然可以使用列表解析的方式替换 map & filter:
  
  [[twoTimes(x), square(x)] for x in L]
  
  [x for x in L if x % 2 == 0]
  
  通过上面的例子我们发现,使用列表推导要比 map 与 filter 简洁且易于理解得多。
  
  但是,我们这里还有一个惰性计算的坑:
  
  f_list = [lambda x:x**i for i in range(5)]
  
  [f_list[j](3) for j in range(5)]
  
  [81, 81, 81, 81, 81]
  
  大家可以思考为什么会出现这个意想不到的结果?

© 著作权归作者所有

SEOwhywhy
粉丝 8
博文 155
码字总数 342404
作品 0
私信 提问
Python - 进阶(持续更新 ing)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/qq39437555/article/details/93867588 文章目录 Python - 面向对象 ...

桃子味儿的汽水~
08/23
0
0
《Python从小白到大牛》简介

本书是一部系统论述Python编程语言、OOP编程思想以及函数式编程思想的立体化教程(含纸质图书、电子书、教学课件、源代码与视频教程)。为便于读者高效学习,快速掌握Python编程方法。本书作...

tony关东升
2018/06/26
0
0
10分钟快速入门Python函数式编程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dQCFKyQDXYm3F8rB0/article/details/82117264 作者 | Brandon Skerritt 译者 | 王天宇、琥珀 编辑 | 琥珀 出品...

AI科技大本营
2018/08/27
0
0
在 Python 中使用函数式编程的最佳实践!

作者 | Amandine Lee 译者 | 弯月 责编 | 屠敏 出品 | CSDN(ID:CSDNNews) 简介 Python 是一种功能丰富的高级编程语言。它有通用的标准库,支持多种编程语言范式,还有许多内部的透明度。如...

CSDN资讯
01/14
0
0
Python函数式编程:从入门到走火入魔

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

好铁
2017/10/21
65
0

没有更多内容

加载失败,请刷新页面

加载更多

最简单的获取相机拍照的图片

  import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import andr......

MrLins
38分钟前
4
0
说好不哭!数据可视化深度干货,前端开发下一个涨薪点在这里~

随着互联网在各行各业的影响不断深入,数据规模越来越大,各企业也越来越重视数据的价值。作为一家专业的数据智能公司,个推从消息推送服务起家,经过多年的持续耕耘,积累沉淀了海量数据,在...

个推
40分钟前
7
0
第三方支付-返回与回调注意事项

不管是支付宝,微信,还是其它第三方支付,第四方支付,支付机构服务商只要涉及到钱的交易都要进行如下校验,全部成功了才视为成功订单 1.http请求是否成功 2.校验商户号 3.校验订单号及状态...

Shingfi
43分钟前
4
0
简述Java内存分配和回收策略以及Minor GC 和 Major GC(Full GC)

内存分配: 1. 栈区:栈可分为Java虚拟机和本地方法栈 2. 堆区:堆被所有线程共享,在虚拟机启动时创建,是唯一的目的是存放对象实例,是gc的主要区域。通常可分为两个区块年轻代和年老代。更...

DustinChan
48分钟前
6
0
Excel插入批注:可在批注插入文字、形状、图片

1.批注一直显示:审阅选项卡-------->勾选显示批注选项: 2.插入批注快捷键:Shift+F2 组合键 3.在批注中插入图片:鼠标右键点击批注框的小圆点【重点不可以在批注文本框内点击】----->调出批...

东方墨天
今天
6
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部