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