函数式编程

函数式编程

高阶函数

一个函数可以接收另一个函数作为参数,这种函数就称之为高阶函数。

map/reduce

map()

map()函数接收两个参数,一个是函数,一个是Iterable(可迭代对象),map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator(迭代器)返回。
例如:使用map函数生成一个x²的数列

def f(x):
	return x * x

r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(r))

[1, 4, 9, 16, 25, 36, 49, 64, 81]

map函数返回的是一个迭代器,使用list()函数将map结果变成列表输出。
list()函数的参数必须是一个可迭代对象,用于生成列表。
将L1中的名字规范为首字母大写,其他字母小写的形式:

def normalize(name):
    str_format = name[0].upper() + name[1:].lower()
    return str_format


# 测试:
L1 = ['adam', 'LISA', 'barT']
L2 = list(map(normalize, L1))
print(L2)

['Adam', 'Lisa', 'Bart']
reduce()

reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

例如对一个序列求和:

from functools import reduce
def add(x, y):
	return x + y

a = reduce(add, [1, 3, 5, 7, 9])
print(a)

25
map与reduce结合使用

例如:把字符串’123.456’转换成浮点数123.456:

def str2float(s):
    num = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}

    a = reduce(lambda x, y: x * 10 + y, map(lambda x: num[x], s.split('.')[0]))
    b = reduce(lambda x, y: x * 10 + y, map(lambda x: num[x], s.split('.')[1]))
    c = b/10**len(s.split('.')[1])
    return a + c


print('str2float(\'123.456\') =', str2float('123.456'))
if abs(str2float('123.456') - 123.456) < 0.00001:
    print('测试成功!')
else:
    print('测试失败!')

输出结果:

str2float('123.456') = 123.456
测试成功!

filter

filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
例如,在一个list中,删掉偶数,只保留奇数:

def is_odd(n):
    return n % 2 == 1

L = list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
print(L)
# 结果: [1, 5, 9, 15]

用filter求素数:
计算逻辑:从2开始的自然数序列,2为素数,先筛选掉2的倍数,剩下的序列中第一个数为3是素数,再筛选掉3的倍数,以此类推

# 构建一个从3开始的奇数数列
def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n

# 建立筛选规则
def _not_divisible(n):
    return lambda x: x % n > 0

# 利用filter创建筛选之后的序列,构建生成器
def primes():
    yield 2
    it = _odd_iter()  # 初始序列
    while True:
        n = next(it)  # 返回序列的第一个数
        yield n
        it = filter(_not_divisible(n), it)  # 构造新序列


# 打印100以内的素数:
for n in primes():
    if n < 100:
        print(n)
    else:
        break

用filter筛选回数

def is_palindrome(n):
    s = str(n)
    return s == s[::-1]  # s[::-1]表示从字符串 s 的末尾到开头,以步长为 -1 进行切片,即反转字符串。


# 测试:
output = filter(is_palindrome, range(1, 100))
print('1~100:', list(output))

1~100: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99]

sorted

Python内置的sorted()函数就可以对list进行排序:

>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]

sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

def by_name(t):
    name = t[0].upper()
    return name


def by_score(t):
    score = t[1]
    return score


L2 = sorted(L, key=by_name)
print("按照名字排序:", L2)
L3 = sorted(L, key=by_score, reverse=True)
print("按照成绩从高到低排序:", L3)

按照名字排序: [('Adam', 92), ('bart', 66), ('Bob', 75), ('Lisa', 88)]
按照成绩从高到低排序: [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('bart', 66)]

reverse=True参数表示进行方向排序

返回函数

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
例如,定义一个求和函数的惰性计算函数:

def lazy_sum(*args):  # *args 是一个特殊的语法,用于在函数定义中表示可以接受任意数量的位置参数。这些参数会被收集到一个元组中。
    print('-> args:', args)

    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum


f = lazy_sum(1, 3, 5, 7, 9)
print(f())

-> args: (1, 3, 5, 7, 9)
25

⚠️函数sum()是lazy_sum的返回函数,f = lazy_sum其实是将f指向了sum(),只有调用f()才会执行求和计算得到计算结果。
⚠️内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种是称为“闭包(Closure)”的程序结构。
⚠️调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数。

使用闭包时,对外层变量赋值前,需要先使用nonlocal声明该变量不是当前函数的局部变量:

def createCounter():
    x = 0

    def counter():
        nonlocal x
        x = x+1
        return x
    return counter


# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA())

1 2 3 4 5

匿名函数

关键字lambda表示匿名函数,冒号前面的x表示函数参数,冒号后面为函数体。
例如:

list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))

lambda x: x * x就相当于:

def f(x):
    return x * x

匿名函数只能写一个表达式,返回值为表达式计算结果,不需要写return。
匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:

f = lambda x: x * x
print(f(2))

4

也可以把匿名函数作为返回值返回:

def build(x, y):
    return lambda: x * x + y * y
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

勇敢磊磊学IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值