小言_互联网的博客

python-高阶函数及闭包的详解和使用

316人阅读  评论(0)

1、高阶函数的特点

什么叫高阶函数呢? 类比数学中的定义,数学中是指三次及以上的幂运算,那在这里我们就能想到至少有两个函数嵌套在一起。

高阶函数有以下两个特点:

  • 接受一个或者多个函数对象作为参数(实际上是传入了函数的各行代码)
  • 将函数对象作为返回值

2、高阶函数

2.1 接受函数作为参数

举个例子,筛选出一个列表中非0的数字:

def notzero(i):
    if i == 0:
        return False
    return True
def filter(list):
    new_list = []
    for i in list:
        if notzero(i):
            new_list.append(i)
    return new_list
filter([0,1,2,0,1,5,0])

"""
out:
[1, 2, 1, 5]
"""

2.2 返回值为函数(也称作闭包)

举个例子,向一个空列表中依次添加数字,每添加一个更新一下平均值。

比较一下下面两段代码和对应的结果:

def average(*arg):
    lis = []
    def math(*arg):
        for i in arg:
             lis.append(i)
        print(len(lis))
        return sum(lis)/len(lis)
    
    return math(*arg)
print(average(5))
print(average(5,10))

"""
out:
1
5.0
2
7.5
"""
def average(*arg):
    lis = []
    def math(*arg):
        for i in arg:
             lis.append(i)
        print(len(lis))
        return sum(lis)/len(lis)
    
    return math
f = average()
f(5)
f(10,5)

"""
out:
1
3
6.666666666666667
"""

不同之处在于,上面的不能连续的添加数字计算平均值,而下面的可以。

原因很简单,因为上面的函数返回值不是函数对象,而是调用函数。这样的话重复的调用外层函数,每次内置的列表都会重新置为0;而下面的代码没有重复调用外层函数,拿到了作为内层函数对象的返回值,重复的调用内层函数,就实现了想要的功能。

那么问题来了,为什么上面的代码不能先拿到内层函数对象呢?我们可以试一下:

def average(*arg):
    lis = []
    def math(*arg):
        for i in arg:
             lis.append(i)
        print(len(lis))
        return sum(lis)/len(lis)
    
    return math(*arg)
f = average()
f(5)
f(10,5)

"""
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-21-3e0b2a49b040> in <module>()
      8 
      9     return math(*arg)
---> 10 f = average()
     11 f(5)
     12 f(10,5)

<ipython-input-21-3e0b2a49b040> in average(*arg)
      7         return sum(lis)/len(lis)
      8 
----> 9     return math(*arg)
     10 f = average()
     11 f(5)

<ipython-input-21-3e0b2a49b040> in math(*arg)
      5              lis.append(i)
      6         print(len(lis))
----> 7         return sum(lis)/len(lis)
      8 
      9     return math(*arg)

ZeroDivisionError: division by zero

"""

它报错了,是因为在

f = average()

的时候,函数进行了调用,内层函数也被调用了,所以出现了

division by zero

这里也能看到高阶函数的好处,就是内置的隐藏数据能够保存着,并且可以拿到内层函数对象。

2.2.1 闭包的好处

为什么要闭包呢?

有时候我们希望某些数据只在函数内部使用,并且不希望别人能够修改它,这时候就用到了闭包。 实际上类似于把一个函数以及函数外的一些数据类型用一个外层函数包装起来。

总结一下就是以下两点:

  • 通过闭包可以创建一些只有当前函数能访问的变量
  • 可以将一些私有数据藏到闭包中

形成闭包的条件:

  • 函数的嵌套
  • 外层函数的返回值是内部函数
  • 内部函数中使用到了外层函数中定义的变量

转载:https://blog.csdn.net/wander_ing/article/details/105927889
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场