函数嵌套定义
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()