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] 
  1. 逐一把iterable的items,传入key指向的函数abs。⚠️abs会运行n次,n等于iterable的项的数量。
  2. 得到keys = [36, 5, 12, 9, 21]
  3. 对上面keys的items进行排序            : [5, 9, 12,   21, 36]
  4. 最终返回的是对应上面排序的原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))

这是Python2.4版本的增加功能

用于增为已经定义的函数/方法增加一些新的功能。装饰器,类似于包装。

在面向对象(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函数本身接收外面的作用域的变量:

  1. 首先, 代码会执行log('execute')返回一个decorator函数,并携带作用域中的字符串'execute';
  2. 然后, 执行decorator(now), 函数now作为参数,  返回wrapper函数本身,它携带字符串'execute'和now函数
  3. 当执行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的更多相关文章

  1. 用scheme重写Python的三大函数map reduce 和filter

    重写过程中,发现这种做法能加深对递归的理解,而且reduce还体现了函数式编程是如何通过参数传递来实现命令式编程中的状态改变的. (define (imap f x . y) (if (null? y ...

  2. Python函数式编程-map/reduce

    1.map map()传入的第一个参数是f,即函数对象本身. map()函数接收两个参数,一个是函数,一个是Interable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterat ...

  3. 函数式编程Map()&Reduce()

    .forEach():每个元素都调用指定函数,可传三个参数:数组元素丶元素索引丶数组本身丶 , , , , , , , ]; a.forEach(function(v,i,a){a[i]=v+;}); ...

  4. Python 中的 map, reduce, zip, filter, lambda基本使用方法

    map(function, sequence[, sequence, ...] 该函数是对sequence中的每个成员调用一次function函数,如果参数有多个,则对每个sequence中对应的元素 ...

  5. Python(十) 函数式编程: 匿名函数、高阶函数、装饰器

    一.lambda表达式 lambda parameter_list: expression # 匿名函数 def add(x,y): return x+y print(add(1,2)) f = la ...

  6. [python基础知识]python内置函数map/reduce/filter

    python内置函数map/reduce/filter 这三个函数用的顺手了,很cool. filter()函数:filter函数相当于过滤,调用一个bool_func(只返回bool类型数据的方法) ...

  7. [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 ...

  8. python基础-函数式编程

    python基础-函数式编程  高阶函数:map , reduce ,filter,sorted 匿名函数:  lambda  1.1函数式编程 面向过程编程:我们通过把大段代码拆成函数,通过一层一层 ...

  9. python 10函数式编程

                                                                               函数式编程 函数是Python内建支持的一种封装, ...

随机推荐

  1. Pytorch构建ResNet

    学了几天Pytorch,大致明白代码在干什么了,贴一下.. import torch from torch.utils.data import DataLoader from torchvision ...

  2. Exchange Server 2010安装

    Exchange Server 2010安装  Exchange Server 2010是Microsoft最新的邮件服务器软件,功能比较强大.在此,我们在虚拟机中安装体验一下,主要步骤如下: (1) ...

  3. Linux 安装 openoffice

    1 说明 本文档采用rpm包方式安装,操作系统为centos 2 下载openoffice rpm包 创建nginx源码包存放目录 mkdir /usr/local/src/openoffice cd ...

  4. 人渣给我笔记本网络适配器里加的的“bluetooth设备(个人局域网)”,卸载不掉

  5. Linux下的I/O复用与epoll详解(转载)

    Linux下的I/O复用与epoll详解 转载自:https://www.cnblogs.com/lojunren/p/3856290.html  前言 I/O多路复用有很多种实现.在linux上,2 ...

  6. Oracle 中 decode 函数用法(字段A,B, C,A不为空则取A,否则取B,B为空则取C)

    –decode(条件,值1,返回值1,值2,返回值2,…值n,返回值n,缺省值) SELECT DECODE(TEMP.SCORE, ‘A’, ‘90-100’, ‘B’, ‘80-89’, ‘C’, ...

  7. Codeforces Round #574 (Div. 2)补题

    A. Drinks Choosing 统计每种酒有多少人偏爱他们. ki 为每种酒的偏爱人数. 输出ans = (n + 1)/2 >  Σki / 2 ? (n + 1)/2 - Σki / ...

  8. apache2_fastcgi_python

    1. 前言 之前有用的是apache2 + python + jon模块下的cgi, fcgi. 该框架搭建的服务器我没有找到能够让python程序持久运行的方法(作为一个服务). 最近看了篇文档, ...

  9. THUSC2016

    补退选 Luogu LOJ BZOJ 比较裸. 建一棵Trie树,记录一下每个节点的\(sum\)表示经过该点的字符串个数,每次暴力插入.删除. 同时每个节点维护一个vector,记录一下这个点的\( ...

  10. linux内核编程入门 hello world

    注意: Makefile 文件的命名注意M需要大写,否则会报错. 在Makefile文件中make命令前应为tab制表符. 下文转载至:https://blog.csdn.net/bingqing07 ...