高阶函数
把函数作为参数传入,这样的函数称为高阶函数
from math import sqrt
def test(x, *func):
ret = list(f(x) for f in func)
return ret
print(test(4, abs, sqrt)) # [4, 2.0]
map函数
map函数接收两个参数,第一个是一个函数,第二个是Iterable,map将传入的函数依次作用到Iterable中的每个元素,并把结果作为新的Iterator返回
# 将名字变为首字母大写,其他小写
def test(elem):
return elem.capitalize()
print(list(map(test, ['adam', 'LISA', 'barT']))) # ['Adam', 'Lisa', 'Bart']
reduce函数
reduce函数接收两个参数,第一个是一个函数,第二个是一个序列,reduce将传入的函数依次作用到Iterable中的每个元素,并把每一个元素的结果与下一个元素作累积计算
from functools import reduce
def str2int(s):
def char2num(c):
# 根据dict中的key来获取value
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[c]
def f(x, y):
return x * 10 + y
return reduce(f, map(char2num, s))
print(str2int("13579")) # 13579
print(type(str2int("13579"))) # <class 'int'>
上面是我们自己写的一个str转int的函数,虽然系统给我们提供了。我们还可以写一个str转float的函数来加强reduce与map的理解
def str2float(s):
# 获取小数点的位置
point = s.index(".")
# 整数部分
num1 = map(int, s[:point])
# 小数部分
num2 = map(int, s[point + 1:])
# 算出小数有多少位
num3 = 1 / 10 ** len(s[point + 1:])
def f(x, y):
return x * 10 + y
return reduce(f, num1) + reduce(f, num2) * num3
print(str2float("126.789")) # 126.789
print(type(str2float("126.789"))) # <class 'float'>
filter函数
filter()
也接收一个函数和一个序列,把传入的函数依次作用于每一个序列的元素,然后根据返回值是True还是False来决定保留还是丢弃该元素。filter()
函数返回的是一个Iterator
def func(elem):
return elem % 2 == 0
print(list(filter(func, list(range(1, 11))))) # [2, 4, 6, 8, 10]
sorted函数
sorted()
可以对一个序列进行排序,也可以接收一个key来实现自定义的排序
l = [36, 5, -12, 9, -21]
print(sorted(l)) # [-21, -12, 5, 9, 36] 从小到大
print(sorted(l, reverse=True)) # [36, 9, 5, -12, -21] 从大到小
print(sorted(l, key=abs)) # [5, 9, -12, -21, 36] 按绝对值的大小排序
对字符串进行排序。对字符串排序是按照ASCII大小比较的,由于'Z'<'a'
,大写字母Z会排在小写字母a的前面,所以可以过字符串的lower方法将先把字符串都变成小写(也可以都变成大写),再比较
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88), ('Zoo', 40)]
def by_name(item):
return item[0].lower()
print(sorted(L, key=by_name)) # [('adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Zoo', 40)]
返回函数
上面学习了将函数作为参数的高阶函数,也可以把函数作为结果值返回
def test(*args):
def f():
ret = 0
for item in args:
ret += item
return ret
return f
result = test(1, 3, 5, 7, 9)
# 返回回来的是一个函数,必须调用才能获取到返回值
print(result()) # 25
print(result) # <function test.<locals>.f at 0x101a7ac80>
我们在函数test中定义了函数f,内部函数f可以引用外部函数test的的参数和局部变量;当函数test返回函数f时,相关参数和变量都保存在返回的函数中,这种称为闭包(Closure)。但这里有一个问题需要注意:
def test2():
fs = []
for i in range(1, 4):
def f():
return i * i
fs.append(f)
return fs
f1, f2, f3 = test2()
print(f1()) # 9
print(f2()) # 9
print(f3()) # 9
这里的结果为什么都是9?
原因在于返回的函数引用了变量i,但它并非立即执行,等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果都是9。
所以,返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量
若一定要引用循环变量怎么办呢?可以这样做:
def test3():
fs = []
def f(x):
def g():
return x * x
return g
for i in range(1, 4):
fs.append(f(i)) # f(i)立即被执行,因此当前i的值被传入到f()函数中
return fs
f4, f5, f6 = test3()
print(f4()) # 1
print(f5()) # 4
print(f6()) # 9
重新创建了一个函数,用该函数的参数与循环变量当前的值进行绑定,无论后绪循环变量如何变,已绑定的函数参数的值不变
匿名函数
结构:
lambda 参数名 : 表达式 或者 lambda : 表达式
如:
print(list(map(lambda x: x * x, [1, 2, 3]))) # [1, 4, 9]
def test(x, y):
return lambda: x + y
print(test(1, 2)()) # 3
装饰器
在代码运行期间动态增加功能的方式称之为装饰器(Decorator)
# 调用函数time时,输出log日志
import functools
def log(func):
# 把原始函数的__name__等属性复制到wrapper()函数中,否则返回出去的__name__属性值为wrapper
@functools.wraps(func)
def wrapper(*args, **kw):
print("call %s():" % func.__name__)
return func(*args, **kw)
return wrapper
# 这里相当于执行:time = log(time)
@log
def time():
print("2017-2-5")
time() # call time(): 2017-2-5
print(time.__name__) # time
自定义一个输出log文本的装饰器
def log2(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print("%s ,%s():" % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
# 这里相当于执行:time2 = log("execute")(time2)
@log2("execute")
def time2():
print("2017-1-5")
time2() # execute ,time2(): 2017-1-5
print(time2.__name__) # time2
首先执行的是log("execute"),返回decorator,再调用返回的函数,参数就是time2,返回值最终是wrapper函数
偏函数
在学习函数参数类型的时候,为了降低函数的调用难度,我们可以设置默认参数。而偏函数也可以做到。
偏函数的作用就是:把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单
def test(x, sqrt=2):
return x ** sqrt
test2 = functools.partial(test, sqrt=3)
print(test2(3)) # 27