python 指南(05)函数式编程

高阶函数

一、编程范式

1、三种编程范式

  • 面向过程:函数封装
  • 面向对象:类封装
  • 函数式:这里的函数是数学上的概念,而不是编程意义上的函数(方法)

2、python的函数式支持

  • 函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数
  • Python对函数式编程提供部分支持,Python允许使用变量,不是纯函数式编程语言
  • 纯函数式编程意味着没有可变变量、赋值、循环和其他的命令式控制结构
  • 纯函数是这样一种函数,即相同的输入永远会得到相同的输出,而且没有任何可观察的副作用

二、高阶函数

  • 变量可以指向函数
  • 函数名也是变量
  • 把函数作为参数传入,这样的函数称为高阶函数

1、map/reduce

  • map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回
  • reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算
str转int方法示例
from functools import reduce

DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}

def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return DIGITS[s]
    return reduce(fn, map(char2num, s))

#使用lambada简化
def char2num(s):
    return DIGITS[s]

def str2int(s):
    return reduce(lambda x, y: x * 10 + y, map(char2num, s))

2、filter

  • filter()也接收一个函数和一个序列,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素
  • filter()的作用是从一个序列中筛出符合条件的元素,由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素
100以内的素数打印
  • 可以用Python表示全体自然数,全体素数这样的序列,代码非常简洁
  • 示例里面就用生成器表示了全体的素数
def odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n


def is_divided(n):
    return lambda x: x % n > 0


def shushu():
    yield 2
    it = odd_iter()
    while True:
        n = next(it)
        yield n
        it = filter(is_divided(n), it)


for i in shushu():
    if i < 100:
        print(i)
    else:
        break

3、sorted

  • sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序
  • 对list进行排序,数字直接比较,其他类型需要我们将比较过程通过函数抽象出来
  • 逆序的话可以使用reverse参数
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
列表里面嵌套元组的排序
  • 形式是这样的:L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
  • 直接使用sorted的话默认是通过名字进行比较,名字相同通过分数比较
  • 可以定义key函数实现直接通过分数排序,key更准确地说是指定排序的依据
def by_score(t):
    return -t[1]

L2 = sorted(L, key=by_score)
print(L2)

返回函数

一、函数做返回值

  • 高阶函数除了函数做参数之外,还可以作为返回值
  • 对于返回函数的高阶函数,我们每调用一次,返回的都是新的函数
  • 返回的函数并不会立刻执行,直到调用了f()才执行

二、闭包

  • 内部函数可以引用外部函数的参数和局部变量,当外部函数返回内部函数时,相关参数和变量都保存在返回的函数中,这就是所谓的 闭包
  • 返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量
def outer_fn():
    name = 'allen'
    age = 12

    def inner_fn():
        print('%s : %s' % (name, age))

    return inner_fn


fn = outer_fn()
fn()

在这里插入图片描述


匿名函数

  • 就是 lambda 函数,具体的写法是这样的:lambda x: x * x
  • : 分割,前面是输入参数,后面是返回结果
  • 后面的方法体的限制是只能有一个语句,语句的计算结果就是返回值,不用写return
  • lambda 函数可以做函数的参数和返回值
  • Python对匿名函数的支持有限,只有一些简单的情况下可以使用匿名函数

装饰器

  • 在代码运行期间动态增加功能的方式,称之为 装饰器(Decorator)

一、两层嵌套的装饰器

1、基本使用说明

  • wrapper 里面的return不写,我测试了一下好像是完全没问题的
  • *args, **kw可以处理所有的参数
def log(func):
    def wrapper(*args, **kw):
        print('20191221')
        return func(*args, **kw)

    return wrapper


@log
def run(text):
    print('test run !!' + text)


run("allen")

2、装饰之后的函数名的变化(__name__

  • 原本run方法的__name__属性的值是run,但是经过装饰之后就变成了wrapper
  • __name__属性的变化会让一些依靠函数签名的代码无法正常工作,可以使用@functools.wraps(func)来解决这个问题,代码如下
import functools


def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('20191221')
        # wrapper.__name__ = func.__name__
        return func(*args, **kw)

    return wrapper


@log
def run(text):
    print('test run !!' + text)


run("allen")
print(run.__name__)

二、三层嵌套的装饰器

  • 装饰器本身还需要传入参数的话,就需要多包装一层
def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            func(*args, **kw)

        return wrapper

    return decorator


@log("haha")
def run():
    print('3 layer test')


run()

# def run():
#     print('3 layer test')
#
#
# log('haha-1')(run)()

偏函数

  • 当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数(也就是设置默认值),从而在调用时更简单
  • 注意这里仅仅是设置了参数的默认值而已,我们进行方法调用的时候对该参数还是可以赋值的
  • 示例中函数int的作用是将字符串转化为整数
import functools

int2 = functools.partial(int, base=2)

print(int2('111'))
print(int2('111', base=10))
# out:
# 7
# 111

发布了153 篇原创文章 · 获赞 51 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/stanwuc/article/details/103632719