一.面向过程
”面向过程“核心是“过程”二字,“过程”指的是解决问题的步骤,即先干什么再干什么......,基于面向过程开发程序就好比在设计一条流水线,是一种机械式的思维方式,这正好契合计算机的运行原理:任何程序的执行最终都需要转换成cpu的指令流水按过程调度执行,即无论采用什么语言、无论依据何种编程范式设计出的程序,最终的执行都是过程式的。
详细的,若程序一开始是要着手解决一个大的问题,按照过程式的思路就是把这个大的问题分解成很多个小问题或子过程去实现,然后依次调用即可,这极大地降低了程序的复杂度。举例如下:
写一个数据远程备份程序,分三步:本地数据打包,上传至云服务器,检测备份文件可用性。
import os,time # 一:基于本章所学,我们可以用函数去实现这一个个的步骤 # 1、本地数据打包 def data_backup(folder): print("找到备份目录: %s" %folder) print('正在备份...') zip_file='/tmp/backup_%s.zip' %time.strftime('%Y%m%d') print('备份成功,备份文件为: %s' %zip_file) return zip_file #2、上传至云服务器 def cloud_upload(file): print("\nconnecting cloud storage center...") print("cloud storage connected") print("upload [%s] to cloud..." %file) link='https://www.xxx.com/bak/%s' %os.path.basename(file) print('close connection') return link #3、检测备份文件可用性 def data_backup_check(link): print("\n下载文件: %s , 验证文件是否无损..." %link) #二:依次调用 # 步骤一:本地数据打包 zip_file = data_backup(r"/Users/egon/欧美100G高清无码") # 步骤二:上传至云服务器 link=cloud_upload(zip_file) # 步骤三:检测备份文件的可用性 data_backup_check(link)
面向过程编程的优点是它可以将复杂的问题流程化,进而简单化。缺点是它的可拓展性极差。面向过程的应用场景大多在软件版本不需要快速更迭,即便是需要更迭也不需要这个软件的所有部分都一起更迭。
二.函数式
函数式编程并非用函数编程这么简单,而是将计算机的运算视为数学意义上的运算,比起面向过程,函数式更加注重的是执行结果而非执行的过程,代表语言有:Haskell、Erlang。而python并不是一门函数式编程语言,但是仍为我们提供了很多函数式编程好的特性,如lambda,map,reduce,filter。
1.匿名函数与lambda
对比使用def关键字创建的是有名字的函数,使用lambda关键字创建则是没有名字的函数,即匿名函数,语法如下:
lambda 参数1,参数2,...: expression
例如:
# 1、定义 lambda x,y,z:x+y+z #等同于 def func(x,y,z): return x+y+z # 2、调用 # 方式一: res=(lambda x,y,z:x+y+z)(1,2,3) # 方式二: func=lambda x,y,z:x+y+z # “匿名”的本质就是要没有名字,所以此处为匿名函数指定名字是没有意义的 res=func(1,2,3)
匿名函数与有名函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,所以匿名函数用于临时使用一次的场景,匿名函数通常与其他函数配合使用,我们以下述字典为例来介绍它。
salaries={ 'siry':3000, 'tom':7000, 'lili':10000, 'jack':2000 }
要想取得薪水的最大值和最小值,我们可以使用内置函数max和min(为了方便开发,python解释器已经为我们定义好了一系列常用的功能,称之为内置的函数,我们只需要拿来使用即可)
res=max(salaries)
res=min(salaries)
内置max和min都支持迭代器协议,工作原理都是迭代字典,取得是字典的键,因而比较的是键的最大和最小值,而我们想要的是比较值的最大值与最小值,于是做出如下改动:
res=max(salaries,key=lambda k:salaries[k])
res=min(salaries,key=lambda k:salaries[k])
同理,我们直接对字典进行排序,默认也是按照字典的键去排序的:
>>> sorted(salaries) ['jack', 'lili', 'siry', 'tom']
2.map、reduce与filter
函数map、reduce、filter都支持迭代器协议,用来处理可迭代对象,我们以一个可迭代对象array为例来介绍它们三个的用法。
array=[1,2,3,4,5]
要求一:对array的每个元素做平方处理,可以使用map函数
map函数可以接收两个参数,一个是函数,另外一个是可迭代对象,具体用法如下:
>>> res=map(lambda x:x**2,array) >>> res <map object at 0x1033f45f8> >>>
解析:map会依次迭代array,得到的值依次传给匿名函数(也可以是有名函数),而map函数得到的结果仍然是迭代器。
>>> list(res) #使用list可以依次迭代res,取得的值作为列表元素 [1, 4, 9, 16, 25]
要求二:对array进行合并操作,比如求和运算,这就用到了reduce函数
reduce函数可以接收三个参数,一个是函数,第二个是可迭代对象,第三个是初始值。
# reduce在python2中是内置函数,在python3中则被集成到模块functools中,需要导入才能使用 >>> from functools import reduce >>> res=reduce(lambda x,y:x+y,array) >>> res 15
解析:
1 没有初始值,reduce函数会先迭代一次array得到的值作为初始值,作为第一个值数传给x,然后继续迭代一次array得到的值作为第二个值传给y,运算的结果为3
2 将上一次reduce运算的结果作为第一个值传给x,然后迭代一次array得到的结果作为第二个值传给y,依次类推,知道迭代完array的所有元素,得到最终的结果15
也可以为reduce指定初始值
>>> res=reduce(lambda x,y:x+y,array,100) >>> res 115
要求三:对array进行过滤操作,这就用到了filter函数,比如过滤出大于3的元素
>>> res=filter(lambda x:x>3,array)
解析:filter函数会依次迭代array,得到的值依次传给匿名函数,如果匿名函数的返回值为真,则过滤出该元素,而filter函数得到的结果仍然是迭代器。
>>> list(res)
[4, 5]
提示:我们介绍map、filter、reduce只是为了带大家了解函数式编程的大致思想,在实际开发中,我们完全可以用列表生成式或者生成器表达式来实现三者的功能。