函数式编程

Edit

函数式编程

特点:允许把函数本身作为参数传入另一个函数,还允许返回一个函数。 
python对函数式编程提供部分支持,由于python允许使用变量,因此,python不是纯函数式编程语言。

高阶函数

定义:一个函数可以接受另外一个函数作为参数,就是高阶函数。 
python可以写高阶函数:

  1. 变量可以指向函数
  2. 函数名也是变量 
    例如:
1.def add(x,y,f):
2.    return f(x)+f(y)
1.>>>add(-5,6,abs)
2.11
map()

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

1.>>> def f(x):
2....     return x * x
3....
4.>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
5.>>> list(r)
6.[1, 4, 9, 16, 25, 36, 49, 64, 81]
reduce()

定义:该函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。 
例如:

1.>>> from functools import reduce
2.>>> def fn(x, y):
3....     return x * 10 + y
4....
5.>>> reduce(fn, [1, 3, 5, 7, 9])
6.13579

举一个同时用mapreduce的例子:

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

定义:fliter()接收一个函数和一个序列,根据传入函数的返回值是Ture还是False决定保留还是丢弃该元素。 
例如:

1.def is_odd(n):
2.    return n % 2 == 1
3.
4.list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
5.# 结果: [1, 5, 9, 15]
sorted()

定义:key函数用来实现自定义排序,reverse=True实现反向排序。 
例如:

  1. 直接进行排序
1.>>> sorted([36, 5, -12, 9, -21])
2.[-21, -12, 5, 9, 36]
  1. 自定义进行排序
1.>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
2.['about', 'bob', 'Credit', 'Zoo']
  1. 反向排序
1.>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
2.['Zoo', 'Credit', 'bob', 'about']

返回函数

函数可以作为返回值
  • 定例子如下:
1.def lazy_sum(*args):
2.    def sum():
3.        ax = 0
4.        for n in args:
5.            ax = ax + n
6.        return ax
7.    return sum
  • 调用时:
1.>>> f = lazy_sum(1, 3, 5, 7, 9)
2.>>> f
3.<function lazy_sum.<locals>.sum at 0x101c6ed90>
4.>>> f()
5.25
  • 注意: 
    当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数
1.>>> f1 = lazy_sum(1, 3, 5, 7, 9)
2.>>> f2 = lazy_sum(1, 3, 5, 7, 9)
3.>>> f1==f2
4.False
闭包
  • 定义:当一个函数返回一个函数时,相关的参数和变量都保存在返回的函数中,这种称为“闭包”。
  • 注意:返回闭包时,返回函数不要引用任何循环变量,或者后续会发生变化的变量,也就是说,返回函数里面的变量必须在这个函数的任何地方都跟外界的函数没有关系的。
  • 错误例子
1.def count():
2.    fs = []
3.    for i in range(1, 4):
4.        def f():
5.             return i*i
6.        fs.append(f)
7.    return fs
8.
9.f1, f2, f3 = count()

·结果

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

结果:

1.>>> f1, f2, f3 = count()
2.>>> f1()
3.1
4.>>> f2()
5.4
6.>>> f3()
7.9

匿名函数

  • 定义:关键字lambda表示匿名函数,冒号前面的x表示函数的参数

例子:

1.>>>list(map(lambda x:x*x,[1,2,3,4,5,6,7]))
2.[1,4,9,16,25,36,49]

相当于:

1.def f(x):
2.    return x*x
  • 注意:只能有一个表达式,不用写return,返回值就是该式的表达结果。
  • 好处: 
    1. 不必担心函数名冲突。
    2. 匿名函数是一个函数对象,可以把匿名函数赋值给一个变量。
    3. 匿名函数可以作为返回值返回。

装饰器

函数也是一个对象,函数对象有一个_name_属性,可以拿到函数名字

  • 定义:在代码运行期间动态增加功能的函数,称为“装饰器”。比如,在函数调用前后自动打印日志,同时又不修改now()函数的定义。
  • 本质是一个返回函数的高阶函数。所以接受一个函数作为参数,并返回一个函数。
  • 使用

例如一个打印日志的decorator

1.def log(func):
2.    def wrapper(*args,**kw):
3.        print('call  %s():' % func._name_)
4.        return func(*args,**kw)
5.    return wrapper

在使用时,我们要借助Python的@语法,把decorator置于函数的定义处:

1.@log
2.def now():
3.    print('2016-8-30')

调用now()函数,不仅会运行now()函数本身,还会运行now()函数前的打印日志函数:

1.>>>now()
2.call now():
3.2016-8-30

这相当于:

1.>>>now=log(now)
  • 高级使用

如果decorator本身需要传入参数,比如要自定义log文本:

1.def log(text):
2.    def decorator(func):
3.        def wrapper(*args, **kw):
4.            print('%s %s():' % (text, func.__name__))
5.            return func(*args, **kw)
6.        return wrapper
7.    return decorator

用法:

1.@log('execute')
2.def now():
3.    print('2016-8-30')

结果:

1.>>>now()
2.execute now():
3.2016-8-30

相当于:

1.>>>now=log('execute')(now)

首先执行log('execute'),返回值是decorator函数,再调用 
返回的函数,参数是now函数,返回值最终是wrapper函数。

  • 注意:

经decorator修饰过的函数,它们的_name_已经从原来的now变成了wrapper了,需要用functools.wraps把函数名字复制下来。 
代码如下:

1.#!/usr/bin/env python3 
2. # -*- coding: utf-8 -*- 
3.
4.
5.import functools 
6.
7.def log(func): 
8.    #@functools.wraps(func) 
9.    def wrapper(*args, **kw): 
10.        print('call %s():' % func.__name__) 
11.        return func(*args, **kw) 
12.    return wrapper 
13.
14.
15.@log 
16.def now(): 
17.    print('2015-3-25') 
18.
19.now() 
20.print(now.__name__)
21.
22.def logger(text): 
23.    def decorator(func): 
24.        @functools.wraps(func) 
25.        def wrapper(*args, **kw): 
26.            print('%s %s():' % (text, func.__name__)) 
27.            return func(*args, **kw) 
28.        return wrapper 
29.    return decorator 
30.
31.@logger('DEBUG') 
32.def today(): 
33.    print('2015-3-25') 
34.
35.today() 
36.print(today.__name__) 

运行结果:

1.call now():
2.2015-3-25
3.wrapper
4.DEBUG today():
5.2015-3-25
6.today

偏函数

  • 定义:functools.partial的作用就是把一个函数的某些参数给固定住(也就是设定默认值),返回一个新的函数,是调用函数变得简单。

例如:

1.def int2(x,base=2):
2.    return int(x,base)

调用时:

1.>>>int2('100000')
2.32

用偏函数实现同样的功能:

1.>>> import functools
2.>>> int2 = functools.partial(int, base=2)
3.>>> int2('1000000')
4.64
5.>>> int2('1010101')
6.85

  
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值