python返回函数学习笔记

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

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..sum at 0x101c6ed90>

调用函数f时,才是真正计算求和的结果

f()
25

当我们调用lazy_sum()时,每次调用都会返回一个新的函数,则f1()和f2()的调用结果互不影响

f1 = lazy_sum(1, 3, 5, 7, 9)
f2 = lazy_sum(1, 3, 5, 7, 9)
f1==f2
False

闭包

辅助理解资料https://zhuanlan.zhihu.com/p/453787908

认识闭包

python作用域的搜索顺序:子对象会一级一级地向上寻找所有父对象的变量

点击查看代码
def f1():
    n=999;

print(n)

运行结果
image
外部函数无法访问内部函数的变量,父对象的所有变量,对子对象都是可见的,反之则不成立
因此,在函数内部再定义一个函数,这个内部函数就可以访问外层函数的变量

点击查看代码
def f1():
    n=999
    def f2():
        print(n)

那么,此时f2()可以访问f1()的局部变量,把f2()作为返回值,就可以在f1()外部读取它内部的变量了

点击查看代码
def f1():
    n=999
    def f2():
        print(n)
    return f2
result = f1()
result()

上述代码f2()函数就是闭包,闭包是内层函数访问完外部变量再返回给外层函数,使得外层函数也可以访问到内部变量
闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。

闭包的用途

  1. 读取函数内部的变量
  2. 让这些变量的值始终保持在内存中

返回的函数在其定义内部引用了局部变量args,一个函数返回了一个函数后,其内部的局部变量还被新函数引用,返回的函数并没有立刻执行,而是直到调用了f()才执行

def count():

fs = []
for i in range(1, 4):
    def f():
         return i*i
    fs.append(f)
return fs

f1, f2, f3 = count()

上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。调用上述三个函数,结果全部都是9,原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量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)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs

nonlocal

使用闭包,就是内层函数引用了外层函数的局部变量。如果只是读外层变量的值,我们会发现返回的闭包函数调用一切正常

点击查看代码
def inc():
    x = 0
    def fn():
        # 仅读取x的值:
        return x + 1
    return fn
	f = inc()
	print(f()) # 1
	print(f()) # 1

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

点击查看代码
def inc():
    x = 0
    def fn():
        # nonlocal x
        x = x + 1
        return x
    return fn

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

使用闭包时,对外层变量赋值前,需要先使用nonlocal声明该变量不是当前函数的局部变量

posted @ 2023-06-14 18:44  鹿丸子  阅读(66)  评论(0)    收藏  举报