20.面向过程与函数式
1. 编程范式
很多初学者在了解了一门编程语言的基本语法和使用之后,面对一个’开发需求‘时仍然会觉得无从下手、没有思路/套路,本节主题“编程范式”正是为了解决该问题,那到底什么是编程范式呢?
编程范式指的就是编程的套路,打个比方,如果把编程的过程比喻为练习武功,那编程范式指的就是武林中的各种流派,而在编程的世界里常见的流派有:面向过程、函数式、面向对象等,本节我们主要介绍前两者。
在正式介绍前,我们需要强调:“功夫的流派没有高低之分,只有习武的人才有高低之分“,在编程世界里更是这样,各种编程范式在不同的场景下都各有优劣,谁好谁坏不能一概而论,下面就让我们来一一解读它们。
2. 面向过程
“面向过程”核心是“过程”二字,**“过程”指的是解决问题的步骤,即先干什么再干什么,基于面向过程开发就好比在设计一条流水,**是一种机械式的思维方式,这正好契合计算机的运行原理:任何程序的执行最终都需要转换成cpu的指令流水按过程调度执行,即无论采用什么语言何种编程范式设计出的程序,最终的执行都是过程式的。
详细的,若程序一开始是要着手解决一个大的问题,按照过程式的思路就是把这个大的问题分解成很多个小问题或子过程去实现,然后依次调用即可,这极大地降低了过程的复杂度。举例如下:
写一个数据远程备份程序,分三步:本地数据打包,上传至云服务器,检测备份文件可用性
mport 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)
面向过程总结:
-
优点、
将复杂的问题流程化,进而简单化
-
缺点
程序的可扩展性极差,因为一套流水或者流程就是用来解决一个问题,就好比制作衣服的生产线无法生产或者说要经过很大的 改动才能生产汽车,修改一个零部件,就会造成连锁反应,而且这一问题会随着程序规模的增大而变得越发的糟糕
-
应用场景
面向过程的程序设计一般用于那些功能一旦实现之后就很少需要改变的场景,比如简单的脚本,去做一些一次性任务,用面向过程去实现是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护,那还是面向对象最为方便。
3. 函数式
函数式编程并非用函数编程这么简单,而是将计算机的运算视为数学意义上的运算,比起面向过程,函数式更加注重的是执行结果而非执行的过程,代表语言有:Haskell、Erlang。而python并不是函数式编程语言,但是任为我们提供了很多的函数式编程好的特性,如lambda,map,reduce,filter
3.1. 匿名函数与lambda
对比使用def关键字创建的是有名字的函数,使用lambda关键字创建则是没有名字的函数,即匿名函数,语法如下
lambda 参数1,参数2,……: x + y
举例
# 1. 定义
lambda x, y: x + y
# 等同于
def func(x, y):
return x + y
#2.调用
# 方式一:
res = (lambda x, y: x + y)(1, 2)
print(res) # 3
# 方式二:
func = lambda x, y: x + y # 此处匿名函数指定名字是没有意义的
res=func(2,3)
print(res) # 5
匿名函数与有名函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,所以匿名函数用于临时使用一次的场景,匿名函数通常与其他函数配合使用,我们用下述字典来介绍它
salaries = {
'siry': 3000,
'tom': 7000,
'lili': 10000,
'jack': 2000
}
要想取得薪水的最大值和最小值,我们可以使用内置函数max和min(为了方便开发,python解释器已经为我们定义好了一系列常用的功能,称之为内置的函数,我们只需要拿来使用即可)
print(max(salaries)) # tom
print(min(salaries)) # jack
内置max和min都支持迭代器协议,工作原理都是迭代字典,取得是字典的键,因而比较的是键的最大和最小值,而我们想要的是比较值的最大值与最小值,于是作出如下改动
# 函数max会迭代字典salaries,每取出一个“人名”就会当作参数传给指定的匿名函数,然后将匿名函数的返回值当作比较依据,最终返回薪资最高的那个人的名字
res = min(salaries, key=lambda k: salaries[k])
print(res) # jack
res = max(salaries, key=lambda k: salaries[k])
print(res) # lili
res1 = sorted(salaries, key=lambda k: salaries[k])
print(res1) # ['jack', 'siry', 'tom', 'lili']
同理,我们直接对字典进行排序,默认也是按照字典的键去排序的
print(sorted(salaries)) # ['jack', 'lili', 'siry', 'tom']
3.2. map、reduce、filter
函数map、reduce、filter都支持迭代器协议,用来处理迭代对象,我们以一个可迭代对象name为例来介绍他们三个的用法
name = ['alex', 'egon', 'kevin', 'tony']
要求一:对name的每个元素加dsb,可以使用map函数,常规使用列表生成器的方式如下
new_name = (n + 'dsb' for n in name)
使用map函数,map函数可以接受两个参数,一个是函数,另外一个是可迭代对象,具体用法如下