Python的函数式编程: map, reduce, sorted, filter, lambda
Python的函数式编程
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。
而函数式编程(请注意多了一个“式”字)——Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。
我们首先要搞明白计算机(Computer)和计算(Compute)的概念。
在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。
而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。
对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
目录
- map
- reduce
- sorted
- filter
- lambda表达式
高阶函数
Python变量可以指向函数
>>> f = abs
>>> f
<built-in function abs>
⚠️函数名也是变量,所有不要在写代码时占用这个名字。
传入函数
因为变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。
内建函数
map
map(function,Iterable)。 它接收2个参数:一个函数,一个Iterable,map把函数作用到Iterable上的每个元素上,返回一个新的Iterator。
>>>list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['', '', '', '', '', '', '', '', '']
⚠️:
- 类似Ruby的map方法,功能一样。ruby的Array#map,直接返回的是aray。
- 而python的map返回的是一个<map object>。它可以被for循环调用,因此是可迭代对象iterable, 但也是iterator。
⚠️: list()是内建函数, class list([iteralble]), 本质是一个可变序列类型。
附加:class list[(iterable)]
- 用一对方括号表示空list: []
- 内部的项items,用逗号分开
- 使用列表生成式:
[x for x in iterable] ,可创建一个列表。
- 使用type constructor: list()或者 list(iterable) , 可创建一个列表。
>>> list('abc')
['a', 'b', 'c']
>>> list( (1,2,3) ) #如果iterable已经是一个列表/tuple, 将创建并返回其副本。
[1, 2, 3]
>>>
functools#reduce
reduce(函数,list) , 传入的函数必须接收两个参数,reduce
把结果继续和序列的下一个元素做累积计算。
练习:
利用map()函数,把不规则输入,转化为首字母大写的名字。
def normalize(name):
b = str.lower(name[1:]) a = str.upper(name[0])
name = a + b
return name L1 = ['adam', 'LISA', 'barT']
L2 = list(map(normalize, L1))
print(L2)
#输出:
['Adam', 'Lisa', 'Bart']
上面用到str.lower() ,str.upper()。
"".join()可以把Iterator,list连接成为一个str。
其实用str.title()语法糖即可。
Python提供的sum()
函数可以接受一个list并求和,请编写一个prod()
函数,可以接受一个list并利用reduce()
求积:
from functools import reduce def prod(L):
def 乘法(x , y):
return x*y
return reduce(乘法, L) print('3 * 5 * 7 * 9 =', prod([3, 5, 7, 9]))
if prod([3, 5, 7, 9]) == 945:
print('测试成功!')
else:
print('测试失败!') #输出
3 * 5 * 7 * 9 = 945
测试成功!
Python支持中文变量。
问题:def是否有作用域?
Python和Ruby这点不一样。
Ruby的def,class,module关键字,代表一个封闭的作用域,任何变量,必须作为参数传入def,才能使用。
Python的def/class,不是封闭的作用域, ,它被执行时,可以读取定义时的外部变量。当然在它内部声明的变量,是局部的,不会影响外部。
Python的def关键字和javascript的函数定义是一样的,非完全封闭的。
sorted函数
sorted(iterable, *, key=None, reverse = False)
根据iterable中的items返回一个新的sorted list。
关键字参数key=None,key是一个带单个参数的函数,用于自定义排序。
这个函数作用于每个iterable的item上,并返回相应的结果,然后对结果排序, 最后sorted返回对应key的排序的iterable的排序。
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
- 逐一把iterable的items,传入key指向的函数abs。⚠️abs会运行n次,n等于iterable的项的数量。
- 得到keys =
[36, 5, 12, 9, 21]
- 对上面keys的items进行排序 :
[5, 9, 12, 21, 36]
- 最终返回的是对应上面排序的原items:
[5, 9, -12, -21, 36]
还可以对str进行比较,原理是根据字符的ASCII的大小比较。 因为ASCII中'Z' < 'a',所以排序的时候要忽略大小写。
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key= str.lower)
['about', 'bob', 'Credit', 'Zoo']
⚠️key指向的函数可以是任何函数,包括自定义的函数。
filter函数
filter(function, iterable)
用function来筛选iterable中的items,根据返回值是True或False来决定是否保留item,构建一个新的iterator。
#类似<filter object at 0x103f1bdf0>
iterable可以是序列,支持迭代的容器, iterator。
filter相当于一个生成器表达式。
(item for item in iterable if function(item))
例子:
def not_empty(s):
return s and s.strip() list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
# 结果: ['A', 'B', 'C']
⚠️:因为在Python,"", None,都代表False。这点和Ruby不同,Ruby中只有nil,false代表false。
>>> bool("")
False
>>> bool(None)
False
例子:用filter求素数(深入理解generator)
lambda表达式
Python的lambda是一个轻量化的函数定义。Python对它定义了一些简单的功能。
因为使用时无需定义一个名字,所以可以看做是python中的匿名函数。
lambda 参数,.. : 主体
lambda相当于def关键字。返回的是主体计算后的结果。
>>> (lambda x: x + 1)(2)
3
因为是表达式,所以也可以给它命名,即给一个变量指向它。
lambda也接收多个参数,例子:
>>> full_name = lambda first, last: f'Full name: {first} {last}'
>>> full_name("hah","ww")
⚠️: f" {} "的写法。
如果没有用变量命名,也可以调用:
>>> lambda x, y: x + y
<function <lambda> at 0x101665dc0>
>>> _(1, 2)
3
从上面的了解可知,Python的lambda好像就是定义一个函数的语法糖。这不像其他语言的lambda。
但需要⚠️的是,lambda就是lambda。它的使用有限制。
语法规则:
- 主体body内只能包括表达式,不能声明变量。
- 只有一行。
- 不支持注释
- 可以被立即调用IIFE: ()()
以上摘录自:https://realpython.com/python-lambda/
更多内容没有看完。
函数装饰器Decorator
函数
- 是对象。
- 可以被赋值给变量。因此可通过变量调用函数。
- 变量._name_: 拿到函数的名字。
⚠️dir(对象)可以拿到一个对象可用的方法。
decorator返回值为另一个函数的函数,通常使用@wrapper语法形式来进行函数变换。常见例子classmethod(), staticmethod()。
装饰器语法只是一种语法糖。可以嵌套使用:
@f1(arg)
@f2
def func(): pass #等价于
def func(): pass
func = f1(arg)(f2(func))
用于增为已经定义的函数/方法增加一些新的功能。装饰器,类似于包装。
在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator可以用函数实现,也可以用类实现。
decorator的简单例子
给now方法加上装饰器log方法。就相当于now = log(now), 即把now函数当成log的参数,now函数的名字__name__重新指向log返回的结果:一个新的函数wrapper。
因此执行方法now,now(),就相当于执行wrapper函数。
def log(func):
def wrapper(*args, **kw):
print('call %s()' % func.__name__)
return func(*args, **kw)
return wrapper @log
def now():
print("") # now = log(now)
now()
这个例子,让decorator函数本身接收外面的作用域的变量:
- 首先, 代码会执行log('execute')返回一个decorator函数,并携带作用域中的字符串'execute';
- 然后, 执行decorator(now), 函数now作为参数, 返回wrapper函数本身,它携带字符串'execute'和now函数
- 当执行now()时,就是执行wrapper()。
# 如果decorator本身需要传入参数, 那么编写一个返回decorator的高阶函数-------------------
# 比如自定义log的文本:
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s()' %(text, func.__name__))
return func(*args, **kw)
# wrapper.__name__ = func.__name__
return wrapper
return decorator @log('execute') #首先, 返回一个decorator函数,并携带外面的作用域中的字符串'execute';然后, decorator接收函数now作为参数,最后返回函数wrapper
def now():
print("") now()
print(now.__name__) # 输出的是 wrapper。因为返回的函数wrapper()的名字就是'wrapper'。 #为了防止有些依赖函数签名的代码执行冲突。加上:wrapper.__name__ = func.__name__ # 可以import functools,然后@functools.wraps(func),代替上面的代码。
Pthon的内建函数classmethod()就是一个装饰器函数。
偏函数
https://docs.python.org/zh-cn/3/library/functools.html#module-functools
Python的函数式编程: map, reduce, sorted, filter, lambda的更多相关文章
- 用scheme重写Python的三大函数map reduce 和filter
重写过程中,发现这种做法能加深对递归的理解,而且reduce还体现了函数式编程是如何通过参数传递来实现命令式编程中的状态改变的. (define (imap f x . y) (if (null? y ...
- Python函数式编程-map/reduce
1.map map()传入的第一个参数是f,即函数对象本身. map()函数接收两个参数,一个是函数,一个是Interable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterat ...
- 函数式编程Map()&Reduce()
.forEach():每个元素都调用指定函数,可传三个参数:数组元素丶元素索引丶数组本身丶 , , , , , , , ]; a.forEach(function(v,i,a){a[i]=v+;}); ...
- Python 中的 map, reduce, zip, filter, lambda基本使用方法
map(function, sequence[, sequence, ...] 该函数是对sequence中的每个成员调用一次function函数,如果参数有多个,则对每个sequence中对应的元素 ...
- Python(十) 函数式编程: 匿名函数、高阶函数、装饰器
一.lambda表达式 lambda parameter_list: expression # 匿名函数 def add(x,y): return x+y print(add(1,2)) f = la ...
- [python基础知识]python内置函数map/reduce/filter
python内置函数map/reduce/filter 这三个函数用的顺手了,很cool. filter()函数:filter函数相当于过滤,调用一个bool_func(只返回bool类型数据的方法) ...
- [py][lc]python高阶函数(匿名/map/reduce/sorted)
匿名函数 - 传入列表 f = lambda x: x[2] print(f([1, 2, 3])) # x = [1,2,3] map使用 传入函数体 def f(x): return x*x r ...
- python基础-函数式编程
python基础-函数式编程 高阶函数:map , reduce ,filter,sorted 匿名函数: lambda 1.1函数式编程 面向过程编程:我们通过把大段代码拆成函数,通过一层一层 ...
- python 10函数式编程
函数式编程 函数是Python内建支持的一种封装, ...
随机推荐
- NDK学习笔记-JNI开发流程
JNI(Java Native Interface)Java本地化接口,Java调用C/C++,C/C++调用Java的一套API接口 实现步骤 在Java源文件中编写native方法 public ...
- SQL介绍、语句之增删改查大全
数据库概念 文件作为数据库,数据格式千差万别 将保存数据的地方统一起来 MySQL一款应用软件 用来帮你操作文件的 只要是基于网络通信,底层都是socket!!! 服务端 -socket通信 -收发消 ...
- 【Python】if __name__ == '__main__' 含义解析
相信大家在看别人的python程序时,可能会在大部分的程序后看到标题这段代码,这里解释下它的意义.总的来说,这句代码的作用就是既能保证当前的.py文件直接运行,也能保证其可以作为模块被其他.py文件导 ...
- 【Python】【demo实验28】【练习实例】【递归函数练习】
原题: 有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁.问第4个人岁数,他说比第3个人大2岁.问第三个人,又说比第2人大两岁.问第2个人,说比第一个人大两岁.最后问第一个人,他说是10岁.请 ...
- FileSystemResource 找不到文件
环境 Spring 3.2.5.RELEASE 原因 使用 FileSystemResource 加载文件的过程中,发现一个奇怪的现象,路径完全正确,但是找不到文件的情况.可能的原因是文件的路径上有压 ...
- springboot整合httpClient
创建httpClientConfig配置类 @Configuration @PropertySource(value="classpath:/properties/httpClient.pr ...
- java中的 |=、&=、^=
|= 关于 |= 运算符:|= 运算符和 += 这一类的运算符一样,拆解开就是 a = a | b: 代码如下: public static strictfp void main(String[] ...
- flask项目配置
config.py: class Config(object): """项目的配置""" DEBUG = True SECRET_KEY = ...
- swagger 报错打不开
1.controller中的接口里使用的 qto的数据类型有问题: qo中的字段中缺少:(@JsonProperty(value = "sort"),以及定义的example值的格 ...
- 配置lombok到eclipse上去
使用maven导入lombok.jar包,可以帮助我们省略掉getter/setting方法. 1.pom.xml 添加依赖: <dependency> <groupId>or ...