从零开始学Python-Day29-返回函数

返回函数顾名思义就是将函数作为返回值返回。一般情况下的求和函数是这样事儿的:

>>> def calc_sum(*args):

ax = 0

for n in args:

ax = ax +n

return ax


>>> calc_sum(1,2,3,4,5)

15

但是有些情况下,我们不希望程序立即计算求和,而是需要时再计算,可以让函数不返回结果,而是返回一个函数:

>>> def lazy_sum(*args):

def sum():

ax = 0

for n in args:

ax = ax + n

return ax

return sum


>>> f = lazy_sum(1,2,3,4,5)

>>> f

.sum at 0x10d696280>

>>> f()

15

可以看到,直接调用lazy_sum时,并没有进行计算,而是返回了一个sum函数,只有调用f()时,才会计算真正的结果。

我们知道这里在lazy_sum中定义了一个sum函数,sum函数成为内部函数,lazy_sum成为外部函数,内部函数可以引用外部函数的参数和变量,而当外部函数lazy_sum返回sum时,相关的参数和变量都保存到了返回的函数中,这种程序称之为闭包(“Closure”)。

值得注意的一点,调用lazy_sum时,每次调用返回的都是一个全新的函数,即使传入参数一致:

>>> f1 = lazy_sum(1,2,3,4,5)

>>> f2 = lazy_sum(1,2,3,4,5)

>>> f1 == f2

False

关于闭包

上面的例子中返回的函数在内部引用了局部变量args,当一个函数返回了新的函数,它的内部变量还会被新的函数引用。下面看一个关于循环的例子:

>>> 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

为什么f1,f2,f3没有按我们预想的一样输出1,4,9呢?因为返回的函数引用了变量i,在for循环结束时i已经变成了3,所以最后结果都是9!

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

如果一定要使用循环变量怎么办?解决的办法就是再创建一个函数,在循环的每一步绑定变量的当前值:

>>> def count():

def f(j):

def g():

return j*j

return g

fs = []

for i in range(1,4):

fs.append(f(i))

return fs


>>> f1,f2,f3 = count()

>>> f1()

1

>>> f2()

4

>>> f3()

9

下面,利用闭包返回一个计数器函数,每次调用它返回递增整数:

>>> def createcounter():

n = 0                                # 先定义一个变量作为初始值

def counter():                      # 定义一个内部函数用来计数

nonlocal n                  # 声明变量n非内部函数的局部变量,否则内部函数只能引用,一旦修改会视其为局部变量,报错“局部变量在赋值之前被引用”

n += 1                      # 每调用一次内部函数,对n + 1

return n                    # 返回n的值

return counter

>>> counterA = createcounter()

>>> print(counterA(), counterA(), counterA(), counterA(), counterA())

1 2 3 4 5

你可能感兴趣的:(从零开始学Python-Day29-返回函数)