函数式编程是一种抽象计算的编程范式。

不同语言的抽象层次不同:计算机硬件->汇编语言->C语言->Python语言

指令        ->           ->函数  ->函数式

计算机————————————>计算

函数式编程的特点:把计算视为函数不是指令

纯函数式编程:不需要变量,没有副作用,测试简单。

支持高阶函数,代码简单。

python作为一种支持函数式编程的语言的特点:

1.不是纯的函数式编程,允许有变量。

2.支持高阶函数,函数也可以作为变量输入

3.支持闭包,有了闭包之后就能够返回函数。

4.有限度的支持匿名函数

高阶函数的特点:

1.变量可以指向函数

>>> abs(-10)
10
>>> abs
<built-in function abs>
>>> f = abs
>>> f(-20)
20

2.函数名其实就是指向函数的一个变量

>>> abs = len
>>> abs([1,2,3])
3

这里面我们将len这个函数名所直接指向的函数赋给了abs,这个时候,abs就能够计算list的长度了。

高阶函数:能够接收函数做参数的函数

>>> def add(x,y,f):
return f(x)+f(y) >>> add(1,-2,abs)
3
>>> add(1,-2,abs())
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
add(1,-2,abs())
TypeError: abs() takes exactly one argument (0 given)

在这里就展示了将函数作为参数,这里面我们的函数只能是传入一个变量名。

map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。

>>> def f(x):
return x*x >>> print (map(f,[1,2,3,4,5,6,7,8,9]))
<map object at 0x0404C9D0>
>>> print (list(map(f,[1,2,3,4,5,6,7,8,9])))
[1, 4, 9, 16, 25, 36, 49, 64, 81]

这里是python3.0的版本,而3.0的版本在生成list的时候我们就需要加一个list,如果是2.0的版本我们就不要添加一个list了

def f(x):
return x*x
print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 10, 25, 36, 49, 64, 81]

reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。

reduce()还可以接收第3个可选参数,作为计算的初始值。

def f(x, y):
return x + y
reduce(f, [1, 3, 5, 7, 9], 100)
125

但是在python3.0版本当中就不包含reduce函数了。如果需要使用的话呢就需要使用from functools import reduce.

>>> def f(x,y):
return x + y >>> from functools import reduce
>>> reduce(f,[1,3,5,7,9])
25
>>> reduce(f,[1,3,5,7,9],100)
125

filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。

>>> def is_odd(x):
return x % 2 == 1 >>> list(filter(is_odd,[1,4,6,7,9,12,17]))
[1, 7, 9, 17]

利用filter(),可以完成很多有用的功能,例如,删除 None 或者空字符串

>>> def is_not_empty(s):
return s and len(s.strip()) > 0 >>> list(filter(is_not_empty,['test',None,'','str',' ','END']))
['test', 'str', 'END']

s.strip(rm) 删除 s 字符串中开头、结尾处的 rm 序列的字符

rm为空时,默认删除空白符(包括'\n', '\r', '\t', ' ')

 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。

>>> sorted([36,5,12,9,21],reverse=True)
[36, 21, 12, 9, 5]

在python3.0中我们进行了改动,只要我们将这个reverse改为True就可以进行倒序的排法,而不需要自己定义新的倒序排法。

由于python3.0和2.0的版本不同,sorted进行了很大的改动。

在Python3.0当中呢我们的比较函数只能有一个函数

>>> def L_upper(x):
return x.lower() >>> sorted(['adam','paul','dean'],key=L_upper,reverse=True)
['paul', 'dean', 'adam']

就如这样,这个key就是前面的list在排序时侯的关键字

Python的函数不但可以返回int、str、list、dict等数据类型,还可以返回函数

>>> def f():
print('call f()...')
def g():
print("call g()...")
return g >>> x=f()
call f()...
>>> x
<function f.<locals>.g at 0x03FB9FA8>
>>> x()
call g()...

在这里面x便是一个函数,也即是那个函数g()

而在打出x()便是调用函数

这种返回函数的操作可以延缓函数的执行。

>>> def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum >>> f=calc_sum([1,2,3,4])
>>> f
<function calc_sum.<locals>.lazy_sum at 0x04232078>
>>> f()
10

而如果没有这种反回函数的功能的话呢

>>> def cal_sum(lst):
return sum(lst) >>> f=cal_sum([1,2,3,4])
>>> f
10

便会直接的进行输出

>>> def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum

上面的代码便是闭包的简单的函数

内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)

闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变

>>> def count():
fs = []
for i in range(1,4):
def f():
return i*i
fs.append(f)
return fs >>> f1,f2,f3 =count()
>>> f1()
9
>>> f2()
9
>>> f3()
9

这里因为i是一个可变的函数所以我们的函数调用三次就会出现变成3

>>> def count():
fs=[]
for i in range(1,4):
def f(m=i):
return m*m
fs.append(f)
return fs >>> f1,f2,f3=count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

我们只要将变量保存在m里面就好了

高阶函数可以接收函数做参数,有些时候,我们不需要显式地定义函数,直接传入匿名函数更方便。

>>> list(map(lambda x: x*x,[1,2,3]))
[1, 4, 9]

关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数

使用匿名函数,可以不必定义函数名,直接创建一个函数对象,很多时候可以简化代码

匿名函数有个限制,就是只能有一个表达式不写return,返回值就是该表达式的结果。

在有些时候返回函数的时候也可以返回匿名函数。

装饰器是为了简化代码的书写而发明的一种语法,在这里我们的装饰器还有一种很简单的调用方法就是@

>>> def log(f):
def fn(x):
print ("call"+f.__name__+'()...')
return f(x)
return fn >>> from functools import reduce
>>> @log
def factorial(n):
return reduce(lambda x,y:x*y,range(1,n+1)) >>> print (factorial(10))
callfactorial()...
3628800

在这里我们调用的只能是一个只包含有一个参数的函数。因为我们在定义的时候说的就是一个包含只有一个参数的函数。

>>> @log
def add(x,y):
return x+y >>> print(add(1,2))
Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
print(add(1,2))
TypeError: fn() takes 1 positional argument but 2 were given

  

 

如上所示我们调用的是一个用有两个参数的add()胡散户,所以系统会报错,这里面报错的理由是fn()拥有的是一个参数,而add()用有的是两个参数,这里就报错了。

要让 @log 自适应任何参数定义的函数,可以利用Python的 *args 和 **kw,保证任意个数的参数总是能正常调用

>>> def log(f):
def fn(*args,**kw):
print('call '+f.__name__+"()...")
return f(*args,**kw)
return fn >>> @log
def factorial(n):
return reduce(lambda x,y:x*y,range(1,n+1)) >>> print (factorial(10))
call factorial()...
3628800
>>> @log
def add(x,y):
return x+y >>> print(add(1,2))
call add()...
3

装饰器也是可以带参数的。比如:在上面输出的时候我们需要简单的表明这些函数是否重要

>>> def log(prefix):#prefix指的是前缀的意思,在这里是随便的命名
def log_decorator(f):
def wrapper(*args,**kw):
print('[%s]%s()...'%(prefix,f.__name__))
return f(*args,**kw)
return wrapper
return log_decorator >>> @log('DEBUG')
def test():
pass >>> print(test())
[DEBUG]test()...
None

由于我们需要添加一个另外的参数所以我们需要在定义的时候就需要添加一个参数,如果这样的话我们就像需要多添加一个循环。

这个三层循环运用了闭包的知识,如果哦我们拆开它就会出现错误,因为最里面的函数调用了外面的参数,所以才会出现错误,如果我们没有装饰器的话呢,我们在其他的编程语言下,就需要使用更多的代码。这也是装饰器的作用。我们学习Python是喜欢它的简洁性、易懂性以及它那超过了两千个库所带来的强大的功能。

而装饰器正是实现这一途径最好的方法。

>>> def log(prefix):
def log_decorator(f):
def wrapper(*args,**kw):
print('[%s]%s()...'%(prefix,f.__name__))
return f(*args,**kw)
return wrapper
return log_decorator >>> @log('DEBUG')
def test():
pass >>> print(test.__name__)
wrapper

在这里面我们会发现我们的函数的名字已经变化了。这种情况就会导致如果我们编写一些需要依赖名字的函数的话我们就会出错。(decorator还改变了函数的__doc__等其它属性。)

如果要让调用者看不出一个函数经过了@decorator的“改造”,就需要把原函数的一些属性复制到新函数中

所以Python内置的functools可以用来自动化完成这个“复制”的任务:

>>> import functools
>>> def log(f):
@functools.wraps(f)
def wrapper(*args,**kw):
print("call...")
return f(*args,**kw)
return wrapper >>> @log
def test():
pass >>> print(test.__name__)
test

但是我们还需要注意一点,就是我们的函数里面的那个参数名有的时候会发生改变的,因为我们的参数虽然是进行了复制,但是参数名是可以进行变化的,因此,即使是只有一个参数的简单函数我们也无法只能简答的保存函数参数最开赋给的那个参数名,而不是后来传入的那个参数名。

int()是我们函数自带的一个转换函数,我们在使用int()进行转换的时候我们会发现int()不止有一个参数,它还有一个参数,这个参数是用来指定,函数的转换进制的。

>>> int ('')
123
>>> int ('',8)
83

其实,int这个函数的第二个函数已经被python给默认是10了,这是为了能够简便我们的输入。这种函数我们称之为偏函数

functools.partial就是帮助我们创建一个偏函数的。

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('')
64
>>> int2('')
85

functools.partial还可以把参数多的函数变为参数少的函数。

pthon之函数式编程的更多相关文章

  1. Python的函数式编程: map, reduce, sorted, filter, lambda

    Python的函数式编程 摘录: Python对函数式编程提供部分支持.由于Python允许使用变量,因此,Python不是纯函数式编程语言. 函数是Python内建支持的一种封装,我们通过把大段代码 ...

  2. angular2系列教程(六)两种pipe:函数式编程与面向对象编程

    今天,我们要讲的是angualr2的pipe这个知识点. 例子

  3. [学习笔记]JavaScript之函数式编程

    欢迎指导与讨论:) 前言 函数式编程能使我们的代码结构变得简洁,让代码更接近于自然语言,易于理解. 一.减少不必要的函数嵌套代码 (1)当存在函数嵌套时,若内层函数的参数与外层函数的参数一致时,可以这 ...

  4. 函数式编程之柯里化(curry)

    函数式编程curry的概念: 只传递给函数一部分参数来调用函数,然后返回一个函数去处理剩下的参数. var add = function(x) { return function(y) { retur ...

  5. 关于Java8函数式编程你需要了解的几点

    函数式编程与面向对象的设计方法在思路和手段上都各有千秋,在这里,我将简要介绍一下函数式编程与面向对象相比的一些特点和差异. 函数作为一等公民 在理解函数作为一等公民这句话时,让我们先来看一下一种非常常 ...

  6. Haskell 函数式编程快速入门【草】

    什么是函数式编程 用常规编程语言中的函数指针.委托和Lambda表达式等概念来帮助理解(其实函数式编程就是Lambda演算延伸而来的编程范式). 函数式编程中函数可以被非常容易的定义和传递. Hask ...

  7. java1.8函数式编程概念

    有关函数式编程 ·1 函数作为一等公民 特点:将函数作为参数传递给另外一个函数:函数可以作为另外一个函数的返回值 ·2 无副作用 函数的副作用指的是函数在调用过程中,除了给出了返回值外,还修改了函数外 ...

  8. 让JavaScript回归函数式编程的本质

    JavaScript是一门被误会最深的语言,这话一点不假,我们看下它的发展历史. 1995年,Netscape要推向市场,需要一门脚本语言来配套它.是使用一门已有的语言,还是发明一门新的语言,这也不是 ...

  9. python基础-函数式编程

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

随机推荐

  1. spring boot: 计划任务@ EnableScheduling和@Scheduled

    spring boot: 计划任务@ EnableScheduling和@Scheduled @Scheduled中的参数说明 @Scheduled(fixedRate=2000):上一次开始执行时间 ...

  2. web自动化:前端页面组成

    一.web页面的组成 1. 常用:HTML + CSS + Javascript 2. HTML:定义页面的呈现内容 3. CSS:Cascading Style Sheets,层叠样式表 控制你的网 ...

  3. linux部署python和加入mysqldb、easy_install

    一.安装easy_install 参考文章: http://www.cnblogs.com/huangjacky/archive/2012/03/28/2421866.html 安装 wget htt ...

  4. xftp5+xshell5工具安装包分享

    身为开发人员,常常为这两个工具安装包找不到资源为难!尴尬了... 这次专门写篇博客,记录资源,并分享给大家. 上链接: 链接:https://pan.baidu.com/s/1mRNxHhr7F2Q_ ...

  5. JSP学习笔记(九十):eclipse3.4中建立控制台程序

    1.控制台程序的建立 File->New->Application Client Project,勾选上Create a default Main class 找到Main.java,修改 ...

  6. 项目管理理论与实践(4)——UML应用(上)

    本篇文章介绍UML的相关知识.参考<UML从入门到精通> 一.UML综述 1. UML简介 统一建模语言(UML)是一个通用的可视化建模语言,用于对软件进行描述.可视化处理.构造和建立软件 ...

  7. Spring_总结_04_高级配置(六)_Bean的初始化和销毁

    一.前言 本文承接上一节:Spring_总结_04_高级配置(五)_运行时注入值

  8. [独孤九剑]Oracle知识点梳理(九)数据库常用对象之package

    本系列链接导航: [独孤九剑]Oracle知识点梳理(一)表空间.用户 [独孤九剑]Oracle知识点梳理(二)数据库的连接 [独孤九剑]Oracle知识点梳理(三)导入.导出 [独孤九剑]Oracl ...

  9. 三、python沉淀之路--列表(list)

    一.列表提供的一些方法 1.append():在原值最后追加 li = [11,22,33,44,55,] li.append(99) print(li) li.append('中国') print( ...

  10. 神秘常量!用0x077CB531计算末尾0的个数,32位数首位相连

    大家或许还记得 Quake III 里面的一段有如天书般的代码,其中用到的神秘常量 0x5F3759DF 究竟是怎么一回事,着实让不少人伤透了脑筋.今天,我见到了一段同样诡异的代码.     下面这个 ...