摘要:看起来好像是废话,它还有一个补充的说明,在函数式编程中要避免状态变化和使用可变对象。函数式编程的特点在中,函数即对象,例如声明一个函数之后,你可以调用其属性。
滚雪球学 Python 第四轮,这一番我们要学习点有难度的了,因此,橡皮擦将降低阅读与理解难度,尽量采用大白话为你铺垫。
这一轮的学习,非常偏理论,因为涉及的一些概念也是借鉴的其它编程语言的风格,而且实际落地中存在部分争议
不过多学一点,总是没有坏处的。
滚雪球学 Python 第四轮,主要学习函数式编程
本系列文章每篇 3000 字左右(包含代码),所以放心享用,不会增大每日学习强度滴
滚雪球历史系列,已完成 3 个专栏,更新中 1 个专栏,即第三轮学习更新中,目前到 21 篇~,由于第三轮是项目实践,学 Django 去,所以第四轮概念类同步开启。
Python 不是纯粹的函数式语言,但你可以使用 Python 进行函数式编程
典型的听君一席话,如听一席话,说白了就是 Python 具备函数式编程的特性,
so,可以借用函数式语言的设计模式和编程技术,把代码写成函数式编程的样子
一般此时我会吹嘘一下,函数式代码比较简洁和优雅~
好了,已经吹嘘完了。
以上内容都属于讲道理的范围,那在 Python 中有哪些适合函数式编程的技能点
又有哪些不适的点呢?
下述 2 点先有个印象就行
reduce
,map
,filter
三巨头。如果你去百度 “什么是函数式编程”,很多地方会给出答案
函数式编程:允许把函数本身作为参数传入另一个函数,还允许返回一个函数。
有道理!
其实函数式编程就是在函数中定义表达式和实现表达式的求职,说白了就是用函数落地你的代码。
看起来好像是废话,它还有一个补充的说明,在函数式编程中要避免状态变化和使用可变对象。
其中避免状态变化 重点要关注赋值语句以及它如何改变状态,因此你在函数式编程中,不会看到 global
,nolocal
等内容。
概念与原理都是比较抽象的,咱还是少说概念,这个留到未来你自己总结就好,直接展示源码差异。
计算 1~100 内,计算 5 与 7 的倍数之和
面向过程的写法
count = 0for num in range(1, 101): if num % 5 == 0 or num % 7 == 0: count += numprint(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 countcount = 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 == 0a = multiple(3) # Falseb = multiple(5) # Truec = multiple(7) # Falseprint(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))
上述代码即为求和的函数式实现,其中部分逻辑如下:
当然还有一种函数式编程的写法,代码如下:
print(sum(n for n in range(1, 101) if n % 5 == 0 or n % 7 == 0))
这里用到的生成器后文会进行说明。
在 Python 中,函数即对象,例如声明一个函数之后,你可以调用其属性。
下述代码展示的即为函数对象的属性,其余内容可以自行再做测试。
def my_func(var1, var2, **kw): return var1 + var2print(type(my_func)) # 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) * 2def one_func(var): return var + 1def two_func(var): return var * 3def three_func(var): return vara = Ext(one_func)print(a(3)) # 8b = Ext(two_func)print(b(3)) # 18c = Ext(three_func)print(c(3)) # 6
上述代码使用了一个新的模块 typing
,该模块是 Python 3.5 之后新增的模块,主要为 Python 提供静态类型的检查 。
本案例中导入的是回调函数 Callable
,格式如下:
Callable[[Arg1Type, Arg2Type],ReturnType]
其中内部中括号 Arg1Type
是参数类型,ReturnType
为返回值类型。
上述三个函数的签名都与 Callable
定义的一致,所以都可以作为 test_demo
参数的值去传递。
滚雪球学Python第四轮,非常理论的一个系列,跟上大部队的节奏,走起来,有任何问题,都可以在评论区留言,一般1小时之内都能解决。
今天是持续写作的第 213 / 365 天。
可以关注,点赞、评论、收藏。
更多精彩
太多了,去主页看吧。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/119554.html
摘要:图片下载属于操作,比较耗时,基于此,可以利用中的多线程将其实现。更多精彩滚雪球学完结滚雪球学第二轮完结滚雪球学第三轮滚雪球学番外篇完结 在 python 编码过程中...
摘要:的安装博客补充知识年最新安装教程,滚雪球学第四季。操作操作数据库一般被程序员成为操作增删改查,其中各个字符分别代表新增,读取,更新,删除。可以返回受影响行数,可以直接通过该值判断是否修改成功。 ...
摘要:尽管如此,还具有高级的数据类型和灵活性。它配备了大量的标准模块,可用于程序库。一些模块提供如下功能通过这些很赞的特性,瞬时化身为面向过程的语言。开发者可以便捷地将解释器连接到一个使用编写的应用程序,并能随时用作扩展。下一部分会继续分享。 【编者按】本文作者是 Abhishek Jaiswal ,擅长 .NET、C#、Python 等多种语言的技术控。本文中,作者通过活泼有趣的口吻向大家...
摘要:项目地址中的函数式编程函数式编程英语或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。 项目地址:https://git.io/pytips Python 中的函数式编程 函数式编程(英语:functional programming)或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且...
摘要:递归函数递归函数的用法递归函数在一个函数里在调用这个函数本身。如来根本不会管师徒四人按照什么流程去取。面向对象的程序优点是解决了程序的扩展性。 递归函数 递归函数的用法: - 递归函数:在一个函数里在调用这个函数本身。 - 递归的最大深度:998 实例 找一个函数的索引位置,递归实现 l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,5...
阅读 998·2021-09-26 09:55
阅读 3533·2021-09-24 10:30
阅读 1344·2021-09-08 09:36
阅读 2534·2021-09-07 09:58
阅读 563·2019-08-30 15:56
阅读 742·2019-08-29 18:32
阅读 3536·2019-08-29 15:13
阅读 1827·2019-08-29 13:49