36.Python基础 学习笔记(高阶函数、返回函数、匿名函数、装饰器、偏函数)

一、高阶函数

1.变量可以指向this

比如Python内置的求绝对值的函数abs(),调用该函数并赋值给变量x,用以下代码:

>>> x = abs(-10)
>>> x
10

只写abs(会得到函数本身):

>>> abs
<built-in function abs>

将函数本身赋值给变量f:

>>> f = abs
>>> f
<built-in function abs>

可以看出函数本身也可以赋值给变量,即变量可以指向函数。

2.函数名也是变量

函数名其实就是指向函数的变量,对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数。

3.传入函数

一个函数接收另一个函数作为参数称为高阶函数

比如:

def add(x, y, f):
    return f(x) + f(y)

当我们调用add(-5,6,abs)时,计算过程为:

x = -5
y = 6
f = abs
f(x) + f(y) ==> abs(-5) + abs(6) ==> 11
return 11

4.map和reduce

(1)map

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

比如我们将一个函数f(x)=x^2 作用在一个list[1,2,3,4,5,6,7,8,9],可以用map实现如下:

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

上边代码最后通过list(r),让它把整个序列都计算出来并返回一个list。

把上边的list所有数字变成字符串,也很简单:

>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']

(2)reduce

reduce把一个函数作用在一个序列上,函数接收两个参数,reduce把结果继续和序列的下一个元素做累积计算:

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

将序列[1,2,3,4,5]变成整数12345,可以用reduce:

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

5.filter

filter()函数用于过滤序列;接收一个函数和一个序列作为参数,filter()把传入的函数依次作用于每个元素,根据返回值是true还是false决定保留还是丢弃该元素。

比如,在一个list中,删掉偶数,只保留奇数:

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

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

filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。

6.sorted

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

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

sorted()函数也是一个高阶函数,可以接收一个key函数,实现自定义排序(比如按绝对值大小进行排序):

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

二、返回函数

1.函数作为返回值

高阶函数除了可以接收函数作为参数之外,还可以把函数作为结果值返回

一个普通的求和函数如下:

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

返回的ax是求和的结果。如果不需要立刻求和,而是在后边代码中,根据需要再求和,那么就可以返回求和的函数:

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

后边想要得到求和结果,需要调用f()这个函数:

>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f()
25

我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

2.闭包

返回闭包时牢记一点:返回的函数不要引用任何循环变量,或者后续会发生变化的变量

如果一定要引用循环变量,可以再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变

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
>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

三、匿名函数

关键字lambda表示匿名函数,冒号前面的x表示函数参数—— lambda x: x * x

比如下边代码,计算(x)= x^2时,可以直接传入匿名函数:

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

匿名函数也是一个函数对象,也可以赋值给一个变量,通过变量来调用该函数

>>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25

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

def build(x, y):
    return lambda: x * x + y * y

四、装饰器

函数对象有一个__name__属性,可以拿到函数的名字:

>>> now.__name__
'now'
>>> f.__name__
'now'

在代码运行期间动态增加功能的方式称为装饰器:

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

上边代码表示函数log接收一个函数作为参数,并返回一个函数。利用Python的@语法,将log函数置于now函数的定义处:

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

调用now函数,不仅会运行now函数本身,还会在运行now函数之前打印一行日志:

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

把@log放到now函数的额定义处,相当于执行了:

now = log(now)

五、偏函数

functools.partial创建一个偏函数,首先先引入functools模块:

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85

functools.partial的作用就是把一个函数的某些参数给固定住,返回一个新的函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值