Python函数式编程实战:从面向过程到函数式的演进与纯函数解析
本文深入解析Python中的函数式编程特性,对比面向过程与面向对象写法,详解map、filter、reduce等核心高阶函数及生成器表达式。通过具体案例演示递归与Lambda表达式的应用,并阐述纯函数、延迟计算及类型提示在提升代码质量中的作用,帮助开发者掌握函数式编程的核心思想与落地技巧。
Python函数式编程
Python并非纯粹的函数式编程语言,但开发者完全可以利用其特性进行函数式编程风格的开发。
简而言之,Python具备支持函数式编程的语言特性,允许开发者采用函数式的思维模式进行编码。
因此,可以借鉴函数式语言的设计模式与编程技术,将代码重构为符合函数式编程规范的形式。
通常情况下,函数式代码因其简洁性和优雅性而备受推崇。
以上是对函数式编程优势的简要概述。
接下来探讨在Python中具体有哪些适合函数式编程的技术点,以及哪些特性可能构成限制。
我们将分析其适用场景与不足之处。
以下两点内容供初步了解,建立直观印象即可。
优点方面,生成器表达式是重点,后文会多次提及;此外Python内置了丰富的高阶函数,其中reduce、map和filter被称为三大核心函数。
缺点方面,Python不支持无限递归等某些函数式语言特有的机制。
若搜索“什么是函数式编程”,多数资料会给出标准定义。
函数式编程允许将函数本身作为参数传递给另一个函数,同时也允许函数返回另一个函数。
这一定义准确概括了函数式编程的核心特征。
实质上,函数式编程是在函数中定义表达式并实现其逻辑,即通过函数来承载和执行业务代码。
这看似是常识,但函数式编程还有一个关键补充:必须避免状态变化和可变对象的使用。
其中,避免状态变化的重点在于关注赋值语句及其对状态的影响,因此在严格的函数式编程中,不应出现global或nolocal等关键字。
通过同一案例的不同实现方式,展示函数式编程的具体应用。
概念与原理较为抽象,此处减少理论阐述,直接通过源码差异进行对比展示。
案例目标:计算1到100之间所有能被5或7整除的数字之和。
面向过程的实现方式
count = 0
for num in range(1, 101):
if num % 5 == 0 or num % 7 == 0:
count += num
print(count)
在面向过程的写法中,逻辑按顺序从上至下执行,例如num变量从1遍历到100,若对5或7取余结果为0,则表明可整除,随后将count累加器与对应的num数值相加,最终得到总和。
这种思路属于典型的面向过程编程,通常是初学者最先掌握的编程方式。
面向对象的实现方式
该写法包含两种路径:一是使用Python内置列表实现,二是自定义类来实现。
第一种写法示例如下:
count = list()
for num in range(1, 101):
if num % 5 == 0 or num % 7 == 0:
count.append(num)
print(sum(count))
在上述代码中,变量count被声明为list类型,即列表对象,但整体结构仍带有过程式编程的痕迹。
例如末尾使用sum(count)的方式显得较为突兀,未能充分体现面向对象的设计思想。
接下来,我们创建一个自定义类来实现逻辑。
class My_List_Sum(list):
def sum(self):
count = 0
for n in self:
count += n
return count
count = My_List_Sum()
for num in range(1, 101):
if num % 5 == 0 or num % 7 == 0:
count.append(num)
print(count.sum())
上述代码中,我们自定义了一个My_List_Sum类,使其继承自list,此时应明确,list即为类名,并在类内部实现了sum方法,随后调用该对象的sum方法,从而完整应用了面向对象的设计模式。
接下来进入核心主题:函数式编程的具体落地实现。
在正式编码前,需回顾基础知识,包括lambda表达式及列表相加操作。
判断一个数字是否为5或7的倍数,使用lambda的写法如下:
multiple = lambda x: x % 5 == 0 or x % 7 == 0 a = multiple(3) # False b = multiple(5) # True c = multiple(7) # False print(a, b, c)
列表相加的代码示例如下:
print([1]+[2]) # [1,2]
基于上述知识,可以编写一个递归函数来实现相应逻辑,代码说明已添加至注释中。
def tool(n: int, end: int, filter_func) -> list:
"""返回一个筛选之后的列表
:param n: 起始值
:param end: 终止值
:param filter_func: 判断表达式
"""
# 如果到达上限,直接返回空列表
if n == end: return []
# 如果满足过滤条件,返回该值与下一个值组成的列表
if filter_func(n):
return [n] + tool(n + 1, end, filter_func)
else:
# 不满足过滤条件,直接返回下一个值
return tool(n + 1, end, filter_func)
# 测试代码
ret = tool(1, 101, lambda x: x % 5 == 0 or x % 7 == 0)
print(ret)
print(sum(ret))
上述代码即为求和功能的函数式实现,其中部分逻辑解析如下:
- 设定初始值与上限值,当迭代值等于上限值时,返回空列表,表示递归结束;
- 传入一个判断条件,本案例中使用lambda表达式,用于筛选5和7的倍数;
- 当满足条件时,执行相加与迭代操作;若不满足条件,则直接进入下一次迭代。
此外,还存在另一种函数式编程的写法,代码如下:
print(sum(n for n in range(1, 101) if n % 5 == 0 or n % 7 == 0))
此处使用的生成器将在后文中详细展开说明。
Python函数式编程的核心特点
在Python中,函数被视为对象,例如声明一个函数后,可以调用其相关属性。
下述代码展示了函数对象的属性,其余内容可自行测试验证。
def my_func(var1, var2, **kw):
return var1 + var2
print(type(my_func)) # <class 'function'>
print(my_func.__code__)
print(my_func.__dict__)
print(my_func.__code__.co_code)
print(my_func.__code__.co_filename)
print(my_func.__code__.co_argcount)
函数式编程高效的原因之一是延迟计算,也称为惰性求值,这些概念将在后文逐步展开,目前先建立初步印象。
正是因为函数即对象,才构成了本文开篇对函数式编程的定义基础。
函数可以接受其他函数作为参数,或返回另一个函数,因此在实际编码中,我们将函数视为其他语言中的“对象”,从而实现函数式编程。
接下来接触Python中的纯函数概念及其实际应用。
纯函数
纯函数是一个重要概念,指函数不对函数外部的作用域产生影响,即其作用域仅限于本地。
简单来说,即在函数内部避免赋值操作,同时应避免使用类似global等关键字。
针对此要求,lambda表达式符合纯函数的定义。
首先查看一个纯函数的示例:
def my_func(num: int) -> int:
return num * 100
上述代码中函数的返回值仅与num参数有关,需满足以下两个条件:
- 不修改全局变量;
- 不更新可变数据结构,如列表或字典。
了解纯函数概念后,下面介绍函数作为对象的具体应用。
在Python中声明一个类时,默认会携带部分内置方法,例如:
from typing import Callable
# 声明一个类,该类无意义,仅测试使用
class Ext:
# 传入的函数,可携带1~2个参数
def __init__(self, test_demo: Callable[[int], int]) -> None:
self.func = test_demo
# 返回结果扩大2倍
def __call__(self, arg: int) -> int:
return self.func(arg) * 2
def one_func(var):
return var + 1
def two_func(var):
return var * 3
def three_func(var):
return var
a = Ext(one_func)
print(a(3)) # 8
b = Ext(two_func)
print(b(3)) # 18
c = Ext(three_func)
print(c(3)) # 6
上述代码使用了一个新模块typing,该模块在Python 3.5之后引入,主要用于为Python提供静态类型检查功能。
本案例中导入的是回调函数Callable,其格式如下:
Callable[[Arg1Type, Arg2Type],ReturnType]
其中内部方括号Arg1Type表示参数类型,ReturnType表示返回值类型。
上述三个函数的签名均与Callable定义一致,因此均可作为test_demo参数的值进行传递。
以上即为Python函数式编程中面向过程、面向对象及函数式风格的简要分析,更多关于Python函数式编程的资料请关注本站其他相关文章。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













