面向过程和函数式

blog 198

前言

在编程界中,常见的变成思想为:面向过程、面向对象、函数式,那么我们把变成思想比喻成武功,那么面向对象和面向过程、函数式则是每个武林派,武功本身没有胜负之分,只是练武功的人有自己独到之处,领悟之深。

本节,我们主要面向过程、和函数式编程

面向过程

面向过程的核心为“过程”二字,面向的意思即为把它当做什么什么去思考。而过程呢,则是做好一件事的完整流程,即先做什么再做什么后做什么...,对自己的功能开发,有着大概的框架即思路。基于面向过程,就好比一个工厂内的流水线,是一种机械式的思维方式。

我们以数据备份功能为例,来了解面向过程的核心思维。

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)

面向过程的优缺点

1、优点

将复杂的问题流程化,进而简单化。

2、缺点

程序的可扩展性非常差

3、应用场景

面向过程编程,一般应用于一些功能一旦写成,后续就很少有改动的场景,比如一些小脚本类似的。

函数式

函数式并非像函数编程那么简单,而是将计算机视为数学运算。比起面向过程,函数式更注重的是结果,而不重视过程。而Python并不是一个函数式编程的编程语言。但是Python也为我们提供了几个比较好的函数式。比如lambda,map、reduc、filter。

匿名函数和lambda

大家都知道,定义一个函数使用的是def关键字,但是def定义的则是有名函数,我们可以通过函数名称()去调用该函数,其实在Python中我们可以使用lambda关键字,去定义一个匿名函数。

lambda关键字的语法

lambda 参数1,参数2,...: expression

示例:

# 定义一个匿名函数

lambda x,y:x + y

# 等同于有名字函数如下:


def f1(x,y):
	return x + y

# 调用一个匿名函数  方法1:

# 语法:(匿名函数表达式)(参数1的值,参数2的值)
print((lambda x,y:x + y)(10,20))

# 调用一个匿名函数 方法2: 函数对象法
func = lambda x,y: x + y
print(func(1,2))

print(lambda x,y: x + y) # <function <lambda> at 0x7f8cf80de2f0> 函数内存地址

如果匿名函数有引用计数为0的时候,那么就会被垃圾回收机制进行回收。所以匿名函数用于临时使用一次的应用场景。还有一种就是匿名函数配合其他函数去使用。

我们使用如下例子进行演示:

# 找出以下value的最大值
salary = {
	'x1ong': 1000,
	'tony': 5000,
	'pony': 300,
	'lili': 2000,
	'hong': 1000
}

我们可以通过max()min()函数,计算一个序列中最大值。

面向过程和函数式
# 找出以下value的最大值
salary = {
	'x1ong': 1000,
	'tony': 5000,
	'pony': 300,
	'lili': 2000,
	'hong': 1000
}

res = max(salary) # 如果不指定key的话,对于字典类型,默认比较的是key。所以我们可以通过key参数指定要比较的值。
print(res) # x1ong

res = max(salary)

指定key之后是这样的:

def func(k):
	return salary[k]

res = max(salary,key=func) # max函数会迭代字典salary,每取出一个人名就会传给func函数的参数k。
print(res)  # tony 的工资最高

但是对于这种只对某个功能,特定义的函数,且下次该函数可能不会在别的地方用到,那么我们就可以将此函数设置为匿名函数。

优化之后的代码:


res = max(salary,key=lambda k:salary[k]) # max函数会迭代字典salary,每取出一个人名就会传给匿名函数的参数k。
print(res) 

介绍完max()函数之后,我们就顺便将与其相反的min()函数学习一下,min()函数可以获取一个序列中最小的值。刚好与max()函数功能相反。

salary = {
	'x1ong': 300,
	'tony': 20,
	'pony': -100,
	'lili': 2,
	'hong': -1
}


res = min(salary,key=lambda k:salary[k]) # 与max()函数同理
print(res) 

同样会有相同的效果。我们可以使用sorted()函数对一个序列进行升序或降序排列

sorted()函数对所有可迭代对象进行排序操作,该函数有如下三个参数:

  • iteratable 可迭代对象
  • key 指定比较的元素
  • reverse 参数reverse=True为降序,为False表示升序
# 找出以下value的最大值
salary = {
	'x1ong': 1000,
	'tony': 5000,
	'pony': 300,
	'lili': 2000,
	'hong': 1000 
}

print(sorted(salary,reverse=True)) # ['x1ong', 'tony', 'pony', 'lili', 'hong'] 

map()函数的应用

map() 会根据提供的函数对指定序列做映射,它可以接受两个参数,参数1为一个函数,参数2为一个可迭代对象,具体的用法如下:

# map的应用

# 假设我们有如下需求,我们需要将list1列表中的每个值的后面加上'_dsb',并且赋值给list2,那么我们应该如何去做?

list1 = ['x1ong','egon','lulu','lxx','zxx','wxx']

'''
list2 = [i + '_dsb' for i in list1] # 列表生成式写法
print(list2)
'''

# 同样的,我们的map函数也是可以做到的,函数本身就有一个映射功能

list2 = map(lambda name:name + '_dsb',list1) # list1这里的list1其实就相当于for i in list1,之后将每次循环得到i的值赋值给了变量name
print(list2) #  <map object at 0x7f8cc01b16a0> 得到一个迭代器对象

# print(next(list2)) # x1ong_dsb
# print(next(list2)) # egon_dsb
# print(next(list2)) # lulu_dsb

# 遍历这个迭代器取值
while True:
	try:
		print(next(list2))
	except StopIteration:
		break

关于map函数的返回值,在Python2中返回的是一个列表,而Python3返回的则是迭代器。

filter()函数的应用

filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。该函数接受的参数为两个参数,参数1为函数,参数2为可迭代对象。可迭代对象的每个元素都会给函数进行判断,会返回TrueFalse,最后将返回为True对应的值存放到新列表中。

# 将list1列表中以dsb结尾的元素赋值到list2列表中

list1 = ['x1ong_dsb','egon','lulu_dsb','lxx','zxx_dsb','wxx']

# 平时的做法
'''
list2 = []
for i in list1:
	if i.endswith('dsb'):
		list2.append(i)
print(list2)
'''
# 列表生成式的做法

list2 = [i for i in list1 if i.endswith('dsb')]
print(list2)

# filter()函数的使用

res = filter(lambda name: name.endswith('dsb'),list2)
print(res) # <filter object at 0x7fc7280216d8>
# print(next(res)) # x1ong_dsb
# print(next(res)) # lulu_dsb
# print(next(res)) # zxx_dsb

# 遍历出这个迭代器的所有值
while True:
	try:
		print(next(res))
	except StopIteration:
		break

reduce()函数的应用

问题:将一个array中的所有数值进行就和

reduce()函数会将参数序列中元素进行累加(求和),该函数有三个参数,参数一为函数,参数二为可迭代对象,参数三位初始值。返回值为函数的运算结果

# coding=utf-8
from functools import reduce # python3的reduce已不是内置函数,它被集成在functools模块下,我们这边调用即可
# 使用sum()函数进行求和
list1 = [10,20,30,40,50,60]

print(sum(list1)) # 210

# 使用for循环解决
res = 0 
for i in list1:
	res += i
 
print(res) # 210

# 使用reduce()函数进行求和
result = reduce(lambda x,y: x + y,list1) 
print(result) # 210

上面示例中对reduce()函数并没有填入参数3,如果没有指定初始值的话,那么可迭代对象中的第一个值,则作为初始值。如果指定了初始值,则就是序列中的每一个值与初始值进行累加。


# 使用reduce()函数进行求和
result = reduce(lambda x,y: x + y,list1) 
print(result) # 210

# 使用reduce()函数进行求和
result = reduce(lambda x,y: x + y,list1,100) 
print(result) # 310

总结:map()函数和filter()函数以及reduce()函数的功能,我们都可以使用列表生成式或者生成器表达式的方式去实现相同的效果。

分享