pthon之函数式编程
函数式编程是一种抽象计算的编程范式。
不同语言的抽象层次不同:计算机硬件->汇编语言->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之函数式编程的更多相关文章
- Python的函数式编程: map, reduce, sorted, filter, lambda
Python的函数式编程 摘录: Python对函数式编程提供部分支持.由于Python允许使用变量,因此,Python不是纯函数式编程语言. 函数是Python内建支持的一种封装,我们通过把大段代码 ...
- angular2系列教程(六)两种pipe:函数式编程与面向对象编程
今天,我们要讲的是angualr2的pipe这个知识点. 例子
- [学习笔记]JavaScript之函数式编程
欢迎指导与讨论:) 前言 函数式编程能使我们的代码结构变得简洁,让代码更接近于自然语言,易于理解. 一.减少不必要的函数嵌套代码 (1)当存在函数嵌套时,若内层函数的参数与外层函数的参数一致时,可以这 ...
- 函数式编程之柯里化(curry)
函数式编程curry的概念: 只传递给函数一部分参数来调用函数,然后返回一个函数去处理剩下的参数. var add = function(x) { return function(y) { retur ...
- 关于Java8函数式编程你需要了解的几点
函数式编程与面向对象的设计方法在思路和手段上都各有千秋,在这里,我将简要介绍一下函数式编程与面向对象相比的一些特点和差异. 函数作为一等公民 在理解函数作为一等公民这句话时,让我们先来看一下一种非常常 ...
- Haskell 函数式编程快速入门【草】
什么是函数式编程 用常规编程语言中的函数指针.委托和Lambda表达式等概念来帮助理解(其实函数式编程就是Lambda演算延伸而来的编程范式). 函数式编程中函数可以被非常容易的定义和传递. Hask ...
- java1.8函数式编程概念
有关函数式编程 ·1 函数作为一等公民 特点:将函数作为参数传递给另外一个函数:函数可以作为另外一个函数的返回值 ·2 无副作用 函数的副作用指的是函数在调用过程中,除了给出了返回值外,还修改了函数外 ...
- 让JavaScript回归函数式编程的本质
JavaScript是一门被误会最深的语言,这话一点不假,我们看下它的发展历史. 1995年,Netscape要推向市场,需要一门脚本语言来配套它.是使用一门已有的语言,还是发明一门新的语言,这也不是 ...
- python基础-函数式编程
python基础-函数式编程 高阶函数:map , reduce ,filter,sorted 匿名函数: lambda 1.1函数式编程 面向过程编程:我们通过把大段代码拆成函数,通过一层一层 ...
随机推荐
- 在Silverlight中使用SESSION
首先Session是运行在服务器上的,而Silverlight运行在客户端.因此在Silverlight中使用SESSION的说法并不准确, 只因大家经常这样搜索才起这个名字. 首先Session ...
- DQN 处理 CartPole 问题——使用强化学习,本质上是训练MLP,预测每一个动作的得分
代码: # -*- coding: utf-8 -*- import random import gym import numpy as np from collections import dequ ...
- iOS 检查指定日期是否在当前日期之前
iOS检查指定日期是否在当前日期之前, 直接上代码: - (BOOL)checkProductDate: (NSString *)tempDate { NSDateFormatter *dateFor ...
- python 实现一个TwoSum的例子
今天无意中看到一个题目,也不是很难,就想着用python实现以下: 题目是数组中的两个数相加等于输入的一个target,然后输出数组的下标. 比如: [1,2,3,4,5,6] target=7 返 ...
- deep learning (五)线性回归中L2范数的应用
cost function 加一个正则项的原因是防止产生过拟合现象.正则项有L1,L2 等范数,我看过讲的最好的是这个博客上的:机器学习中的范数规则化之(一)L0.L1与L2范数.看完应该就答题明白了 ...
- Git_学习_09_指定某些文件不上传
一.前言 在git提交文件到远程分支时,可能有些文件我们并不想上传. 这时可以使用如下命令来将这些文件从暂存区移除 git rm --cached "文件路径" 注:git add ...
- LeetCode OJ:Summary Ranges(概括区间)
Given a sorted integer array without duplicates, return the summary of its ranges. For example, give ...
- BEC translation exercise 4
People have long known that nuts are part of a healthy diet.人们早就知道坚果是健康饮食的一部分.People, who you know w ...
- git教程5-查看关系图与no fast forward融合
1.每一个提交相当于一个版本,版本都有版本号与之对应.通常通过git commit -m "name"为每次提交命名. 2.融合:即将次分支的最后一个版本添加到主分支上.当融合冲突 ...
- codeforces 755F F. PolandBall and Gifts(贪心+多重背包)
题目链接: F. PolandBall and Gifts time limit per test 1.5 seconds memory limit per test 256 megabytes in ...