Python基础--函数的嵌套和闭包
1、名称空间与作用域
1 名称空间分为:
1 内置名称空间 内置在解释器中的名称
2 全局名称空间 顶头写的名称
3 局部名称空间
2 找一个名称的查找顺序:先在局部名称空间找,再到全局名称空间找,再到内置名称空间
3 Globals() 查看全局名称空间的内容
Locals() 查看局部名称空间的内容
4 全局作用域包含内置名称空间和全局名称空间
局部作用域包含局部名称空间
例
1 查看内建名称空间的内容:
2 作用域
1 x=1 2 def foo(): 3 x=100 4 print(x) 5 foo() 6 print(x)
输出结果
1 100 2 1
3 一定要注意函数要先定义,后使用
1 def foo(): 2 print("from foo") 3 bar() 4 def bar(): 5 print("from bar") 6 foo()
输出结果:
1 from foo 2 from ba
1 def foo(): 2 print("from foo") 3 bar() 4 foo() 5 def bar(): 6 print("from bar")
输出结果:
1 NameError: name 'bar' is not defined #报错
4 Globals() 查看全局名称空间的内容
Locals() 查看局部名称空间的内容
1 x=1 2 def func(): 3 print("from func") 4 x=2 5 print(globals()) 6 print(locals()) 7 func() 8 print(globals()) 9 print(locals())
输出结果:
1 from func 2 {'x': 1, '__cached__': None... 3 {'x': 2} 4 {'x': 1, '__cached__': None... 5 {'x': 1, '__cached__': None...
2、函数嵌套与静态嵌套域
嵌套调用
嵌套调用作用:将一个大的功能细化成各种小的函数功能并调用
1 def my_max(x,y): 2 res=x if x >y else y 3 return res 4 print(my_max(10,100)) 5 def my_max4(a,b,c,d): 6 res1=my_max(a,b) 7 res2=my_max(res1,c) 8 res3=my_max(res2,d) 9 return res3 10 print(my_max4(1,20,3,4))
输出结果:
1 100 2 20
在函数内定义的函数 在外面不能用到
1 def f1(): 2 def f2(): 3 def f3(): 4 pass 5 print("---->f1") 6 f2() 7 f2()
输出结果:
1 NameError: name 'f2' is not defined #报错
#嵌套定义
x找值的过程:先在局部名称空间找,再到上一级的局部名称空间找,再到全局名称空间找,再到内置名称空间
1 x=0 2 def f1(): 3 #x=1 4 print("---f1---",x) 5 def f2(): 6 #x=2 7 print("---f2---",x) 8 def f3(): 9 #x=3 10 print("---f3---",x) 11 f3() 12 f2() 13 f1()
输出结果:
1 ---f1--- 0 2 ---f2--- 0 3 ---f3--- 0
3、函数对象
函数被称为第一类对象,函数可以被当做数据传递
(1)函数可以被赋值
直接输出函数名的值: 就是函数在内存中的地址
1 def foo(): 2 print("foo") 3 print(foo)
输出结果:
1 <function foo at 0x000000DD32CAAD90>
函数可以被赋值:将函数名代码的值赋给变量
1 def foo(): 2 print("foo") 3 f=foo 4 print(f) 5 f()
输出结果:
1 <function foo at 0x0000003AEBEBAD90> 2 foo
(2)函数可以作为参数传递
函数可以作为参数传递
1 def foo(): 2 print("foo") 3 def bar(func): 4 print(func) 5 func() 6 print(bar(foo))
输出结果:
1 <function foo at 0x000000A351B4AD90> 2 foo 3 None
(3)函数可以作为返回值
函数可以作为函数的返回值
1 def foo(): 2 print("foo") 3 def bar(func): 4 print(func) 5 func() 6 return func 7 f=bar(foo) 8 print(f) 9 f()
输出结果:
1 <function foo at 0x000000BFD82CAD90> 2 foo 3 <function foo at 0x000000BFD82CAD90> 4 foo
(4)函数可以作为容器类型的元素
函数作为字典的键的值:
1 def add(): 2 print("=======>function add") 3 def search(): 4 print("=======>function search") 5 def delete(): 6 print("=======>function delete") 7 def change(): 8 print("=======>function change") 9 def tell_msg(): 10 msg=''' 11 search:查询 12 add:添加 13 delete:删除 14 change:修改 15 create:新建 16 ''' 17 print(msg) 18 def create(): 19 print('=======>function create') 20 21 cmd_dic={ 22 'search':search, 23 'add':add, 24 'delete':delete, 25 'change':change, 26 'create':create 27 } 28 while True: 29 tell_msg() 30 choice=input("please input your choice:") 31 cmd_dic[choice]()
4、函数闭包
(1)函数闭定义
闭包:首先必须是内部定义的函数,该函数包含对外部作用域而不是全局作用域名字的引用
定义:内部函数的代码包含对外部函数的代码的引用,但一定不是对全局作用域的引用
闭包的基本形式是:
在函数F1中,定义F2,F2只能引用F1定义的变量,之后F1函数返回F2的函数名字
这样就保证了可以将F1的执行结果赋予给一个变量,该变量可以在之后的任何时刻随时可以运行
使用闭包的好处:自带状态即变量,可以不用传参就用,方便。
闭包(closure)是函数式编程的重要的语法结构。不同的语言实现闭包的方式不同。Python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看到Python使用对象来实现一些特殊的语法)。Python一切皆对象,函数这一语法结构也是一个对象。在函数对象中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。
(2)简单闭包举例
1 x=1000 2 def f1(): 3 x=1 4 def f2(): 5 print(x) 6 return f2 7 f=f1() 8 print(f) 9 x=123
输出结果:
1 <function f1.<locals>.f2 at 0x000000C02BD1AF28> 2 1
(3)闭包的__closure__变量
闭包都有__closure__属性
__closure__对象会返回闭包应用外围作用域的变量信息。f.__closure__保存外围作用域的变量内存地址,f.__closure__[0].cell_contents存放的是外围作用域的变量的值。
对于那些不是闭包的函数对象来说,__closure__ 属性值为 None。
1 x=1 2 def f1(): 3 x=1000 4 y=2 5 def f2(): 6 y 7 print(x) 8 return f2 9 f=f1() #f ---> 内部的函数f2 10 f() 11 print(f.__closure__) 12 print(f.__closure__[0]) 13 print(f.__closure__[0].cell_contents) 14 print(f.__closure__[1]) 15 print(f.__closure__[1].cell_contents)
输出结果:
1 1000 2 (<cell at 0x000000429E165D68: int object at 0x000000429E0A9EB0>, <cell at 0x000000429E165D98: int object at 0x0000000059C0EF50>) 3 <cell at 0x000000429E165D68: int object at 0x000000429E0A9EB0> 4 1000 5 <cell at 0x000000429E165D98: int object at 0x0000000059C0EF50> 6 2
举例:__closure__ 属性值为 None
1 x=1 2 def f1(): 3 def f2(): 4 print(x) 5 return f2 6 f=f1() #f ---> 内部的函数f2 7 f() 8 print(f.__closure__)
输出结果为:
1 1 2 None
(4)闭包应用
Windows中cmd中执行pip install requests 安装requests库件
爬baidu网站的程序
1 from urllib.request import urlopen 2 def get(url): 3 return urlopen(url).read() 4 print(get('http://www.baidu.com')) 5 print(get('http://www/python.org'))
将上面”爬百度”的程序修改成闭包模式:
1 from urllib.request import urlopen 2 def f1(url): 3 def f2(): 4 print(urlopen(url).read()) 5 return f2 6 baidu=f1('http://www.baidu.com') 7 python=f1('http://www.python.org') 8 baidu() 9 python()
一、名称空间和作用域
名称空间:Python所有有关命名的操作都是在操作名称空间,例如变量名,函数名 1、内置名称空间:Python解释器提供好的功能,解释器启动跟着一起启动,是全局作用域 2、全局名称空间:Python中顶行写的,不在函数内部定义的,都是全局名称空间,在运行的时候会产生名称空间,是全局作用域 3、局部名称空间:在一个小范围定义,只能当前范围及其子空间内运行,例如在函数内部定义的,是局部作用域
二、函数的嵌套
1、函数的嵌套调用 2、函数的嵌套定义
1 x = 1111111111111111 2 def f1(): 3 #x=1 4 print('------>f1 ',x) 5 def f2(): 6 #x = 2 7 print('---->f2 ',x) 8 def f3(): 9 x=3 10 print('-->f3 ',x) 11 f3() 12 f2() 13 f1()
三、函数的使用
1、函数可以被当做变量赋值
1 def foo(): 2 print("foo") 3 print(foo) #打印foo的内存地址空间,函数的名字在不带小括号时表示的是函数的内存地址 4 f=foo #把foo的内存地址空间做值赋值给f变量 5 print(f) #打印f,起始就是打印foo的内存地址空间 6 f() #f()事实上就是执行foo函数,等同于foo() 7 8 9 打印结果为 10 <function foo at 0x0000000000B91378> #print(foo)的结果 11 <function foo at 0x0000000000B91378> #print(f)的结果 12 foo #执行f()的结果,实际就是执行foo()的结果
2、函数可以当做参数传递
1 def foo(): 2 print("foo") 3 print(foo) #打印foo的内存地址空间 4 f=foo #把foo的内存地址空间做值赋值给f变量 5 print(f) #打印f,起始就是打印foo的内存地址空间 6 f() #f()事实上就是执行foo函数,等同于foo() 7 8 def bar(func): 9 print(func) #这个是打印foo()函数的内存地址 10 func() #func是foo的内存地址,加()实际就是执行foo()函数 11 return func 12 f = bar(foo) #这个是获取bar的返回值 13 print(f) #打印f,就是打印bar()的返回值,就是foo()的内存地址,和print(func)相同 14 f() #f是bar 15 16 def bar(func): 17 print(func) 18 19 bar(foo()) #这个是先执行foo()行数,执行函数里的代码,先打印foo,然后把foo()的返回值作为bar()函数的实参传递给bar,foo()没有返回值,所以是None 20 #结果就是先输出一个 "foo" 然后bar(None),把none传递给bar()函数,打印No
四、闭包:内部函数的代码包含对外部作用域的引用,但一定不是对全局作用域的引用,闭包函数一定有__closure__方法
1 x=1 2 def f1(): 3 x=2 4 y=3 5 def f2(): 6 print(x) 7 y 8 return f2 9 f=f1() #f是f2的内存地址 10 f() #f()就是f2(),可以保证f2()可以在任何位置执行,而不受作用域的限制 11 print(f.__closure__) #打印结果是元组,元组个数代表的是闭包所引用的上次函数的元素个数 12 print(f.__closure__[0]) #结果是元组,可以使用索引的方式查看 13 print(f.__closure__[0].cell_contents) #查看指定元组所对应的应用上层参数的值 14 15 def init(func): 16 def wrapper(*args,**kwargs): 17 res=func(*args,**kwargs) 18 return res 19 return wrapper 20 21