python学习笔记 day10 函数嵌套定义和闭包

函数嵌套定义

def func1():
    a=1
    def func2():
        print(a) #内部函数可以使用外部函数的变量
    func2()
func1()

外层函数func1中嵌套定义了内层函数func2,并且在外层函数中定义的变量a,在内层函数func2中也可以使用;

外层函数中的变量a是int 类型不可变数据类型,内层函数中只可以查看不可以修改;

如果需要修改,可以使用nonlocal声明局部变量:(类似于在函数体中使用global 声明全局变量修改)

a=0 #全局变量
def func1():
    a=50 #外层函数中变量a是不可变数据类型;
    def func2():
        a=2
        def func3():
            nonlocal a
            a+=100 #改变的是上一层离该函数最近的func2()中的a值
        func3()
        print("func2():a",a)  # 102
    func2()
    print("func1():a",a)  # 50
func1()
print("全局:a",a)  # 0

运行结果:

nonlocal 只作用于局部变量;只修改上一层中离该内层函数最近的函数中的变量,;

如果在所有的上层函数中都找不到要修改的该局部变量,则报错(因为nonlocal只作用于局部变量,global声明的才是全局变量)

函数名其实就是内存地址,函数名可以赋值:

def func1():
    print("hello world")
func1()
func2=func1  #函数名可以相当于变量进行赋值操作;这样func2和func1这两个函数名都可以指向同一个内存地址
func2()

函数名可以作为容器类型的参数:

def func1():
    print("hello world")
# func1()
func2=func1  #函数名可以相当于变量进行赋值操作;这样func2和func1这两个函数名都可以指向同一个内存地址
# func2()

L=[func1,func2]
for func in L:
    func() #func1() func2()

函数名可以作为另一个函数的参数:

def func1():
    print("hello world!")

def func2(f):  #参数是一个函数名,而不是普通的变量~
    f()
    print("hello world~")

func2(func1)

函数名可以作为另一个函数的返回值:

def func1():
    def func2():
        print("hello world!")
    return func2  #将内部定义的函数func2函数名返回
f=func1()  #因为func1()函数返回的就是一个函数 f=func2
f() #func2()

 闭包:---嵌套函数;内部函数必须要调用外部函数中的变量

def func1():
    a=1 #外部函数中定义的变量
    def func2():  
        print(a)
    return func2  #把一个函数名作为返回值
f=func1()  #f=func2
f()

如果内层函数不调用外部函数中的变量,或者调用的是全局变量都不能称之为闭包函数(闭包指的是内层函数):

a=1
def func1():
    # a=1 #外部函数中定义的变量
    def func2(): #使用的是全局变量a,不是闭包函数
        print(a)
    return func2  #把一个函数名作为返回值
f=func1()  #f=func2
f()

一般写其实可以保护外部函数中被内层函数使用的变量,延长存在周期:

def func1():
    a=1
    print(a)
func1()  #会创建一个局部变量a,随着函数func1()执行完会被释放;
func1()  #又会创建一个局部变量a,,,,随着函数func1的调用会被重复创建;

 推荐做法(使用闭包):

def func1():
    a=1
    def func2():
        print(a)
    return func2  #外部函数返回的其实是一个函数名;
f=fun1() #f是一个全局变量,它指向一个内部函数,随时可以进行调用f() 所以外部函数的a并不会随着函数的结束而被释放,而是会留在内部命名空间中,等待f()时被调用
f()

这样a变量不会随着f()的调用重复创建,随着func1()函数执行完毕被释放掉,而是由于f全局变量(其实是一个函数名=func2)可能被调用会留在内部命名空间中;

 比如其实再写爬虫,爬取一些网站时我们也可以使用闭包:在多次调用函数时不用重复创建url变量:

不建议:

from urllib.request import urlopen
def get_url():  #未使用闭包,这样每次调用get_url()时就会重复创建url变量
    url='http://www.xiaohua100.cn/index.html'
    res=urlopen(url).read()
    print(res)    
get_url()

推荐使用闭包:

from urllib.request import urlopen
def get_url():  #使用闭包,这样每次调用get_url()时就不会重复创建url变量
    url='http://www.xiaohua100.cn/index.html'
    def inner():   #闭包函数
        res=urlopen(url).read()
        print(res)
    return inner
inn=get_url()  #全局变量inn指向内层函数,由于inn()随时可能被调用,随意外层函数的url会保留在局部命名空间中;
inn()
inn()
talk is cheap,show me the code
原文地址:https://www.cnblogs.com/xuanxuanlove/p/9560367.html