python—函数式编程

函数式编程

  • 纯函数式编程没有变量,一个函数只要输出确定,输出就是确定的,称为没有副作用.使用变量的函数内部由于变量状态不确定性,有副作用.
  • 函数式编程另一个特点是允许函数本身作为参数传入,也可以直接返回另外一个函数.
  • python对函数式编程提供有限支持.(还使用变量 so不是纯函数式编程语言)

高阶函数

  • python中函数本身也可以赋值给变量,变量可以指向函数
  • 函数的参数可以传入另一个函数,这种函数称为高阶函数.

map/reduce

  • map()接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回

  • 示例

    1
    list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]) # list所有数字转为字符串
  • reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> from functools import reduce
    >>> def fn(x, y):
    ... return x * 10 + y
    ...
    >>> def char2num(s):
    ... digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
    ... return digits[s]
    ...
    >>> reduce(fn, map(char2num, '13579'))
    13579

filter

  • filter()接收一个函数和一个序列。filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

  • filter()函数返回的是一个 惰性序列 Iterator,也就是一个惰性序列,需要用list()函数获得所有结果并返回list

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def is_odd(n):
    return n % 2 == 1

    list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) # 只保留奇数

    def not_empty(s):
    return s and s.strip()

    list(filter(not_empty, ['A', '', 'B', None, 'C', ' '])) # 删除空字符

sorted

  • sorted()函数接收一个key函数来实现自定义的排序.第三个参数reverse=True决定正序倒序.

  • 示例:

    1
    2
    3
    4
    5
    >>> sorted(['bob', 'about', 'Zoo', 'Credit'],key=str.lower)
    ['about', 'bob', 'Credit', 'Zoo']

    >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
    ['Zoo', 'Credit', 'bob', 'about']

返回函数

  • 将函数作为结果返回.(很随便😂)

  • 闭包(Closure):相关参数和变量都保存在返回函数.

  • **note:**返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用

  • 示例(坑):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def count():
    fs = []
    for i in range(1, 4):
    def f():
    return i*i
    fs.append(f)
    return fs

    f1, f2, f3 = count()

    >>> f1()
    9
    >>> f2()
    9
    >>> f3()
    9
  • 返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9

  • 一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def count():
    def f(j):
    def g():
    return j*j
    return g
    fs = []
    for i in range(1, 4):
    fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
    return fs

匿名函数

  • 不显式定义的函数. python中是 lambda 但与java不同.

  • python中lambda限制,只能有一个表达式,不用写return,返回值就是该表达式的结果

  • 匿名函数不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数

  • 示例

    1
    f = lambda x: x * x

装饰器

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

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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
  • 如示例,装饰器 接受一个函数作为参数,并返回原函数.在原函数定义时,以 @ xxx作为标记.示例1 为2层,如果打印文本可以自定义.

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def log(text):
    def decorator(func):
    def wrapper(*args, **kw):
    print('%s %s():' % (text, func.__name__))
    return func(*args, **kw)
    return wrapper
    return decorator

    @log('execute')
    def now():
    print('2015-3-25')

    >>> now()
    execute now():
    2015-3-25

    打印可自定义 又加上了一层.

  • 如上两种定义后,函数对象的名称等发生了变化,so,终极版

  • Python内置的functools.wraps 会将原始函数的__name__等属性复制到wrapper()函数中.

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import functools
    # 不带参数
    def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
    print('call %s():' % func.__name__)
    return func(*args, **kw)
    return wrapper

    # 带参数

    def log(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

偏函数

  • functools.partial的作用是把一个函数的某些参数设置默认值,返回一个新的函数.

  • 示例:

    1
    2
    3
    4
    import functools
    int2 = functools.partial(int, base=2)

    int2('1000000')
  • 注意: 仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值

  • 由于python 中函数也可以最为参数传入,so,参数固定成某一个函数也可.

  • 同理: *args**kw 也可以.

  • 简化函数调用.