函数式编程
基于lanbda演算的一种编程方式
- 程序中只有函数
- 函数可以作为参数,也可以作为返回值
- 纯函数式编程语言:LISP, Haskell
Python函数式编程只是借鉴函数式编程的一些特点,可以理解为一半函数式一半Python
lambda表达式
函数能够最大程度复用代码
函数存在的问题
- 如果函数很小,很短,则会造成啰嗦
- 如果函数调用次数少,则会造成浪费
- 对于阅读者来说,则会造成阅读流程的被迫中断
lambda表达式(匿名函数):
- 一个表达式,函数体相对简单
- 不是一个代码块,仅仅是一个表达式
- 可以有参数,多个参数用逗号隔开
用法
- 以lambda开头
- 紧跟一定的参数(可以没有)
- 参数后用冒号和表达式主体隔开
- 只是一个表达式,没有return
#例子
#计算一个数的一百倍
stm = lambda x : 100*x
使用上和函数一样
stm(98)
#三个数相加
stm = lambda x,y,z :x+y+z
stm(1,2,3)
高阶函数
把函数作为参数使用的函数叫做高阶函数
函数名就是一个变量
def funA():
print(A)
funB = funA
funB()
#高阶函数例子
#普通实现
def funA(n): #把一个数扩大一百倍
return n*100
def funB(n): #把一个数扩大三百倍
return funA(n) * 3
#高阶函数实现
def funC(n, f):
return f(n) * 3
print(funC(9, funA))
系统高阶函数
map
原意就是映射,即把集合或者列表的元素每一个都按照一定的规则进行操作,生成一个新的列表或者集合,map函数是系统提供的具有映射功能的高级函数,返回的是一个迭代对象
map(fun,可迭代对象)
reduce(需要导入functools包)
- 原意是归并,缩减
- 把一个可迭代对象最后归并成一个结果
- 对于作为参数的函数要求:必须有两个参数,必须返回结果
reduce([1,2,3,4,5]) == f(f(f(f(1,2),3),4),5)
filter
过滤函数:对一组数据进行过滤,符合条件的数据会生成一个新的列表并返回
- 利用给定函数进行判断
- 返回值是一个可迭代filter对象
filter(过滤函数,数据)
与map对比
相同 | 不同 | |
---|---|---|
map | 都会对列表的每一个元素进行逐一操作 | map会生成一个和原来数据一一对应的新队列filter则不一定,只有符合条件的才会进入新队列 |
sorted
排序函数:
sorted(data, key= , reverse=False(升序)/reverse=True(降序))
abs:绝对值
#例子
a = [5, 43, -54, 99]
rst = sorted(a, key = abs, reverse = True)
print(rst)
返回函数
函数可以返回具体的值也可以返回一个函数作为结果
#例子
def F2():
def F3():
print("In f3")
return 3
return F3
f3 = F2()
f3()
zip
把两个可迭代的内容生成一个可迭代的tuple元素类型组成的内容
l1 = [ ]
l2 = [ ]
z = zip(l1,l2)
enumerate
跟zip功能比较像对可迭代对象里的每一个元素配上一个索引,生成一个tuple对象
l1=[]
em = enumerate(l1)
l2 = [i for i in em]
print(l2)
#-----------------------
em = enumerate(l1, start = 100)
l2 = [i for i in em]
print(l2)
collections模块
- namedtulpe:是一个可命名的tuple类,通过名字来访问元组元素
#例子
Circle = collections.namedtuple("Circle",["x","y","z"])
c =Circle(100,150,50)
print(c)
print(type(c))
isinstance(c,tuple)
- deque:双向队列,比较方便的解决了频繁插入删除带来的效率问题
#例子
from collections import deque
q = deque(["a","b","c"])
print(q)
q.append("d")
print(q)
q.appendleft("x")
print(q)
- defaultdict:值带有默认类型的字典当,直接读取dict不存在的属性时,直接返回默认值,程序不崩溃
#例子
from collections import defaultdict
func = lambda: "xxx"
d1 = defaultdict(func)
d1['one'] = 1
d2['tow'] = 2
print(d1['one'])
print(d1['four'])
- Counter:统计字符串的个数
#例子
from collections import Counter
#为什么下面结果不把“abcdefasfdsa”作为键值而是以其中每一个字母作为键值
#因为需要括号里面的内容为可迭代
c = Counter("abcdefasfdsa")
print(c)
s = ["12","asd","ass","12"]
c = Counter(s)
print(c)
闭包(closure)
当一个函数在内部定义函数,并且内部的函数应用外部函数的参数或者局部变量,当内部函数被当作返回值的时候,相关参数和变量保存在返回的函数中,这种结果叫做闭包
#常见闭包坑
def count():
fs = []
for i in rang(1, 5):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
#理想结果为1,4,9,16
#结果为16,16,16,16
出现这种问题的原因是:返回函数引用了变量i,i并非立即执行,而是等到三个函数都返回的时候才统一使用,此时i已经变成了4,最终调用的时候都是返回4*4
所以返回闭包时,返回函数不能引用任何循环变量
解决方案:在创建一个函数,用该函数的参数绑定循环变量的当前值,
无论该循环变量以后如何改变,已经绑定的函数参数值不再改变
#修改后代码
def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in rang(1, 5):
fs.append(f(i))
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
装饰器
在不改动函数代码的基础上无限制扩展函数功能的一种机制,本质上讲,装饰器是一个返回函数的高阶函数
用法:使用@语法,即在每次要扩展到函数定义前使用@+函数名
#例子
#对hello函数进行功能扩展。每次执行hello前打印当前时间
import time
def printTime(f):
def wrapper(*args, **kwargs):
print("Time:",time.ctime())
return f(*args, **kwargs)
return wrapper
#上面定义了装饰器,使用时需要用到@,此符号时python的语法糖
@printTime
def hello():
print("Hello World")
hello()
装饰器的好处:一点定义,则可以装饰任意函数,一旦被其装饰,则把装饰器的功能直接添加到定义函数上
上述调用是利用@语法糖,下面这种直接调用装饰器
def hello2()
print("2222")
hello2 = printTime(hello2)
hello2()
偏函数
参数固定的函数,相当于一个由特定参数的函数体
#例子
#创建一个函数返回十六进制数为十进制
def int16(int, base = 16):
return int(x,base)
#利用偏函数实现上面int16的功能
import functoosl
int16 = functools.partial(int, base=16)
#functools.partia的作用,把一个函数某些函数固定,返回一个新函数
#调用
int16("65454")