• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >python > 用Python进行基础的函数式编程的教程

用Python进行基础的函数式编程的教程

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了python函数式编程,函数式编程,函数式编程语言,javascript函数式编程,js函数式编程等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

许多函数式文章讲述的是组合,流水线和高阶函数这样的抽象函数式技术。本文不同,它展示了人们每天编写的命令式,非函数式代码示例,以及将这些示例转换为函数式风格。

文章的第一部分将一些短小的数据转换循环重写成函数式的maps和reduces。第二部分选取长一点的循环,把他们分解成单元,然后把每个单元改成函数式的。第三部分选取一个很长的连续数据转换循环,然后把它分解成函数式流水线。

示例都是用Python写的,因为很多人觉得Python易读。为了证明函数式技术对许多语言来说都相同,许多示例避免使用Python特有的语法:map,reduce,pipeline。
导引

当人们谈论函数式编程,他们会提到非常多的“函数式”特性。提到不可变数据1,第一类对象2以及尾调用优化3。这些是帮助函数式编程的语言特征。提到mapping(映射),reducing(归纳),piplining(管道),recursing(递归),currying4(科里化);以及高阶函数的使用。这些是用来写函数式代码的编程技术。提到并行5,惰性计算6以及确定性。这些是有利于函数式编程的属性。

忽略全部这些。可以用一句话来描述函数式代码的特征:避免副作用。它不会依赖也不会改变当前函数以外的数据。所有其他的“函数式”的东西都源于此。当你学习时把它当做指引。

这是一个非函数式方法:

 
a = 0
def increment1():
  global a
  a += 1
</div>

这是一个函数式的方法:

 
def increment2(a):
  return a + 1
</div>

不要在lists上迭代。使用map和reduce。
Map(映射)

Map接受一个方法和一个集合作为参数。它创建一个新的空集合,以每一个集合中的元素作为参数调用这个传入的方法,然后把返回值插入到新创建的集合中。最后返回那个新集合。

这是一个简单的map,接受一个存放名字的list,并且返回一个存放名字长度的list:

 
name_lengths = map(len, ["Mary", "Isla", "Sam"])
 
print name_lengths
# => [4, 4, 3]
</div>

接下来这个map将传入的collection中每个元素都做平方操作:

 
squares = map(lambda x: x * x, [0, 1, 2, 3, 4])
 
print squares
# => [0, 1, 4, 9, 16]
</div>

这个map并没有使用一个命名的方法。它是使用了一个匿名并且内联的用lambda定义的方法。lambda的参数定义在冒号左边。方法主体定义在冒号右边。返回值是方法体运行的结果。

下面的非函数式代码接受一个真名列表,然后用随机指定的代号来替换真名。

 
import random
 
names = ['Mary', 'Isla', 'Sam']
code_names = ['Mr. Pink', 'Mr. Orange', 'Mr. Blonde']
 
for i in range(len(names)):
  names[i] = random.choice(code_names)
 
print names
# => ['Mr. Blonde', 'Mr. Blonde', 'Mr. Blonde']
</div>

(正如你所见的,这个算法可能会给多个密探同一个秘密代号。希望不会在任务中混淆。)

这个可以用map重写:

 
import random
 
names = ['Mary', 'Isla', 'Sam']
 
secret_names = map(lambda x: random.choice(['Mr. Pink',
                      'Mr. Orange',
                      'Mr. Blonde']),
          names)
</div>

练习1.尝试用map重写下面的代码。它接受由真名组成的list作为参数,然后用一个更加稳定的策略产生一个代号来替换这些名字。

 
names = ['Mary', 'Isla', 'Sam']
 
for i in range(len(names)):
  names[i] = hash(names[i])
 
print names
# => [6306819796133686941, 8135353348168144921, -1228887169324443034]
</div>

(希望密探记忆力够好,不要在执行任务时把代号忘记了。)

我的解决方案:

 
names = ['Mary', 'Isla', 'Sam']
 
secret_names = map(hash, names)
</div>

Reduce(迭代)

Reduce 接受一个方法和一个集合做参数。返回通过这个方法迭代容器中所有元素产生的结果。

这是个简单的reduce。返回集合中所有元素的和。

 
sum = reduce(lambda a, x: a + x, [0, 1, 2, 3, 4])
 
print sum
# => 10
</div>

x是迭代的当前元素。a是累加和也就是在之前的元素上执行lambda返回的值。reduce()遍历元素。每次迭代,在当前的a和x上执行lambda然后返回结果作为下一次迭代的a。

第一次迭代的a是什么?在这之前没有迭代结果传进来。reduce() 使用集合中的第一个元素作为第一次迭代的a,然后从第二个元素开始迭代。也就是说,第一个x是第二个元素。

这段代码记'Sam'这个词在字符串列表中出现的频率:

 
sentences = ['Mary read a story to Sam and Isla.',
       'Isla cuddled Sam.',
       'Sam chortled.']
 
sam_count = 0
for sentence in sentences:
  sam_count += sentence.count('Sam')
 
print sam_count
# => 3
</div>

下面这个是用reduce写的:

 
sentences = ['Mary read a story to Sam and Isla.',
       'Isla cuddled Sam.',
       'Sam chortled.']
 
sam_count = reduce(lambda a, x: a + x.count('Sam'),
          sentences,
          0)
</div>

这段代码如何初始化a?出现‘Sam'的起始点不能是'Mary read a story to Sam and Isla.' 初始的累加和由第三个参数来指定。这样就允许了集合中元素的类型可以与累加器不同。
为什么map和reduce更好?

首先,它们大多是一行代码。

二、迭代中最重要的部分:集合,操作和返回值,在所有的map和reduce中总是在相同的位置。

三、循环中的代码可能会改变之前定义的变量或之后要用到的变量。照例,map和reduce是函数式的。

四、map和reduce是元素操作。每次有人读到for循环,他们都要逐行读懂逻辑。几乎没有什么规律性的结构可以帮助理解代码。相反,map和reduce都是创建代码块来组织复杂的算法,并且读者也能非常快的理解元素并在脑海中抽象出来。“嗯,代码在转换集合中的每一个元素。然后结合处理的数据成一个输出。”

五、map和reduce有许多提供便利的“好朋友”,它们是基本行为的修订版。例如filter,all,any以及find。

练习2。尝试用map,reduce和filter重写下面的代码。Filter接受一个方法和一个集合。返回集合中使方法返回true的元素。

 
people = [{'name': 'Mary', 'height': 160},
     {'name': 'Isla', 'height': 80},
     {'name': 'Sam'}]
 
height_total = 0
height_count = 0
for person in people:
  if 'height' in person:
    height_total += person['height']
    height_count += 1
 
if height_count > 0:
  average_height = height_total / height_count
 
  print average_height
  # => 120
</div>

如果这个比较棘手,试着不要考虑数据上的操作。考虑下数据要经过的状态,从people字典列表到平均高度。不要尝试把多个转换捆绑在一起。把每一个放在独立的一行,并且把结果保存在命名良好的变量中。代码可以运行后,立刻凝练。

我的方案:

 
people = [{'name': 'Mary', 'height': 160},
     {'name': 'Isla', 'height': 80},
     {'name': 'Sam'}]
 
heights = map(lambda x: x['height'],
       filter(lambda x: 'height' in x, people))
 
if len(heights) > 0:
  from operator import add
  average_height = reduce(add, heights) / len(heights)
</div>

写声明式代码,而不是命令式

下面的程序演示三辆车比赛。每次移动时间,每辆车可能移动或者不动。每次移动时间程序会打印到目前为止所有车的路径。五次后,比赛结束。

下面是某一次的输出:

 
-
--
--
 
--
--
---
 
---
--
---
 
----
---
----
 
----
----
-----
</div>

这是程序:
 

from random import random
 
time = 5
car_positions = [1, 1, 1]
 
while time:
  # decrease time
  time -= 1
 
  print ''
  for i in range(len(car_positions)):
    # move car
    if random() > 0.3:
      car_positions[i] += 1
 
    # draw car
    print '-' * car_positions[i]
</div>

代码是命令式的。一个函数式的版本应该是声明式的。应该描述要做什么,而不是怎么做。
使用方法

通过绑定

您可能想查找下面的文章:

  • 总结Python编程中函数的使用要点
  • Python函数式编程指南(四):生成器详解
  • Python函数式编程指南(三):迭代器详解
  • Python函数式编程指南(二):从函数开始
  • Python函数式编程指南(一):函数式编程概述
  • 利用Fn.py库在Python中进行函数式编程
  • 用Python进行基础的函数式编程的教程
  • Python装饰器的函数式编程详解

相关文章

  • 跟老齐学Python之变量和参数
  • 在Python的web框架中中编写日志列表的教程
  • python修改操作系统时间的方法
  • Python实现单词拼写检查
  • python使用xlrd实现检索excel中某列含有指定字符串记录的方法
  • tensorflow如何继续训练之前保存的模型实例
  • Python保存MongoDB上的文件到本地的方法
  • python实现封装得到virustotal扫描结果
  • 介绍Python的Django框架中的静态资源管理器django-pipeline
  • Python构造函数及解构函数介绍

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • python通过pil将图片转换成黑白效果的方法
    • Python实现八大排序算法
    • python实现class对象转换成json/字典的方法
    • SublimeText 2编译python出错的解决方法(The system cannot find the file specified)
    • NumPy排序的实现
    • python实现倒计时的示例
    • Python内置函数Type()函数一个有趣的用法
    • 使用Python的Twisted框架编写简单的网络客户端
    • 在Python上基于Markov链生成伪随机文本的教程
    • python实现文本文件合并

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有