函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。
而函数式编程(请注意多了一个“式”字)——Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数, 只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由 函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。
``在Python中,对匿名函数提供了有限支持。还是以map()函数为例,计算f(x)=x^2时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:
>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25
stm = lambda x,y,z: x*x+y*y
stm(2,3,4)
def build(x, y):
return lambda: x * x + y * y
def rtnBrandon():
return "brandon"
def rtnJohn():
return "john"
def rtnPerson():
age = int(input("What's your age?"))
if age == 21:
return rtnBrandon()
else:
return rtnJohn()
语法:
结果序列 = map(映射函数,序列1[,序列2,....])
[1, 2, 3, 4, 5]
x = [1, 2, 3, 4, 5]
def square(num):
return num*num
print(list(map(square, x)))
enumerate(): 【这个是用于for 循环的】可以将列表或元组生成一个有序号的序列。【序号就是下表,因为是有序的】
Python 中的函数式函数也有“懒”的特性。如果我们不引入 “list()”,那函数就会存取 iterable 对象,而不是存取列表本身。我们需要明确告诉 Python 程序 “将其转换成列表” ,从而供我们使用。
这个函数简单的理解为自定义规则进行累加、累乘等操作。前一个结果作为新计算过程的操作数。比如1 + 1 = 2 ,结果2参与 下一次运算 2+ 3 = 5 ,该次reduce(1,1,3)结果为5.
reduce()函数的作用就是将序列中的所有元素作为参数,按照一定的规则调用指定函数。
映射函数必须有2个参数。
从Python 3.0开始,reduce()不再被集成在Python内置函数中,需要使用 from functools import reduce 才能调用reduce()
语法:
计算结果 = reudce(映射函数, 序列)
对指定序列执行过滤操作。
其定义:
filter(函数 function, 序列 sequence)
function接收一个参数,返回值为布尔值。序列可以是列表、元组、字符串。
filter()以序列参数sequence中的每个元素为参数调用function函数,调用结果为True的元素最后将作为filter()函数的结果返回。
语法如下:
filter(function, list)
案例
x = range(-5, 5)
new_list = []
for num in x:
if num < 0:
new_list.append(num)
x = range(-5, 5)
all_less_than_zero = list(filter(lambda num: num < 0, x))
a = [1,2,3,4,5,6]
al = sorted(a)
print(al)
# 倒序
al = sorted( a, reverse = =True)
print(al)
# 排序案例2
a = [-1,2,3 -2 ,-4,5 ,-5,7]
# 按绝对值进行排序
# abs是求绝对值的意思,,即按照绝对值的倒序排列
al = sorted(a, key=abs,reverse= True)
print(al)
# 定义一个普通函数
def myF(a):
print('In myF')
return None
a = myF(8)
print(a)
# 函数作为返回值返回,被返回的函数在 函数体内定义
def myF2():
def myF3():
print("In myF3")
return 3
return myF3
# 使用上面定义
# 调用没有F2,返回一个函数 myF3,赋值给f3
f3 = myF2()
print(type(f3))
print(f3)
f3()
def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>
>>> f()
25
lazy_sum
中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum
的参数和局部变量,当lazy_sum
返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。python中,闭包closure指的是函数的嵌套。可以在函数内部定义一个嵌套函数,将嵌套函数看作一个对象,所以可以将嵌套函数作为定义它的函数的返回结果。
递归函数就是直接或者间接调用函数本身的函数。
def now():
print('2016-11-22')
f = now
f()
# 2016-11-22
>>> now.__name__
'now'
>>> f.__name__
'now'
现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2015-3-25')
>>> now()
call now():
2015-3-25
now = log(now)
由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。
wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
这个3层嵌套的decorator用法如下:
@log('execute')
def now():
print('2015-3-25')
Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。
在介绍函数参数的时候,我们讲到,通过设定参数的默认值,可以降低函数调用的难度。而偏函数也可以做到这一点。举例如下:
int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:
>>> int('12345')
12345
>>> int('12345', base=8)
5349
>>> int('12345', 16)
74565
def int2(x, base=2):
return int(x, base)
>>> int2('1000000')
64
>>> int2('1010101')
85
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
所以,简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:
>>> int2('1000000', base=10)
1000000
int2 = functools.partial(int, base=2)
int2('10010')
相当于:
kw = { 'base': 2 }
int('10010', **kw)