廖雪峰 | 5.1 返回函数和匿名函数

返回函数

1,实例1:可变参数求和
(1)即时返回求和结果

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

(2)返回求和函数,调用该函数则得结果

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum
#调用lazy_sum()函数
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>
#调用f()函数,得求和结果
>>> f()
25
  • 在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种程序称为“闭包(Closure)”
  • 调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数,结果函数也不相同
>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False
>>> f1()
25
>>> f2()
25

2,实例2(闭包):依次返回1,2,3的平方数值

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

3,实例3(nonlocal):返回递增整数的计数器函数
(1)如果只是读外层变量的值,返回的闭包函数调用一切正常:

def inc():
    x = 0
    def fn():
        # 仅读取x的值:
        return x + 1
    return fn

f = inc()
print(f()) # 1
print(f()) # 1

(2)如果对外层变量赋值,由于Python解释器会把x当作函数fn()的局部变量,它会报错:

def inc():
    x = 0
    def fn():
        # nonlocal x
        x = x + 1
        return x
    return fn

f = inc()
print(f()) # 1
print(f()) # 2

原因是x作为局部变量并没有初始化,直接计算x+1是不行的。但我们其实是想引用inc()函数内部的x,所以需要在fn()函数内部加一个nonlocal x的声明。加上这个声明后,解释器把fn()x看作外层函数的局部变量,它已经被初始化了,可以正确计算x+1

  • 使用闭包时,对外层变量赋值前,需要先使用nonlocal声明该变量不是当前函数的局部变量。
    (3)练习:利用闭包返回一个计数器函数,每次调用它返回递增整数:
# -*- coding: utf-8 -*-
def inc():
    x = 0
    def fn():
        nonlocal x
        x = x + 1
        return x
    return fn

# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
    print('测试通过!')
else:
    print('测试失败!')

匿名函数

1,匿名函数:lambda表示

  • 关键字lambda表示匿名函数,冒号前面的x表示函数参数
  • 匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果
  • 匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
  • 可以把匿名函数作为返回值返回
>>> 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

2,练习
问:请用匿名函数改造下面的代码:

# -*- coding: utf-8 -*-
def is_odd(n):
    return n % 2 == 1

L = list(filter(is_odd, range(1, 20)))

#改造后
L = list(filter(lambda n: n%2 == 1, range(1, 20)))
print(L)
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容