目錄html
1、python內部的原理
2、命名空間
3、做用域
4、global關鍵字、nonlocal關鍵字
5、函數名的本質
6、閉包python
7、總結網絡
1、python內部的原理閉包
Python代碼運行的時候遇到函數是怎麼作的,從Python解釋器開始執行以後,就在內存中開闢裏一個空間,每當遇到一個變量的時候,就把變量名和值之間對應的關係記錄下來,可是當遇到函數定義的時候,解釋器只是象徵性的將函數名讀如內存,表示知道這個函數存在了,至於函數內部的變量和邏輯,解釋器根本不關心。
等執行到函數調用的時候,Python解釋器會再開闢一塊內存來儲存這個函數裏面的內容,這個時候,才關注函數裏面有哪些變量,而函數中的變量回儲存在新開闢出來的內存中,函數中的變量只能在函數內部使用,而且會隨着函數執行完畢,這塊內存中的全部內容也會被清空。
咱們給這個‘存放名字與值的關係’的空間起了一個名字-------命名空間。
代碼在運行伊始,建立的存儲「變量名與值的關係」的空間叫作全局命名空間;
在函數的運行中開闢的臨時的空間叫作局部命名空間。app
2、命名空間less
1 >>> import this 2 The Zen of Python, by Tim Peters 3
4 Beautiful is better than ugly. 5 Explicit is better than implicit. 6 Simple is better than complex. 7 Complex is better than complicated. 8 Flat is better than nested. 9 Sparse is better than dense. 10 Readability counts. 11 Special cases aren't special enough to break the rules.
12 Although practicality beats purity. 13 Errors should never pass silently. 14 Unless explicitly silenced. 15 In the face of ambiguity, refuse the temptation to guess. 16 There should be one-- and preferably only one --obvious way to do it. 17 Although that way may not be obvious at first unless you're Dutch.
18 Now is better than never. 19 Although never is often better than *right* now. 20 If the implementation is hard to explain, it's a bad idea.
21 If the implementation is easy to explain, it may be a good idea. 22 Namespaces are one honking great idea -- let's do more of those!
在python之禪中提到過:命名空間是一種絕妙的理念,讓咱們盡情的使用發揮吧!ide
命名空間一共分爲三種:
全局命名空間:建立的存儲「變量名與值的關係」的空間叫作全局命名空間
局部命名空間:在函數的運行中開闢的臨時的空間叫作局部命名空間
內置命名空間:內置命名空間中存放了python解釋器爲咱們提供的名字:input,print,str,list,tuple...它們都是咱們熟悉的,拿過來就能夠用的方法。函數
三種命名空間之間的加載順序和取值順序:ui
加載順序:內置命名空間(程序運行前加載)===>全局命名空間(從上到下順序加載進來的)===>局部命名空間(函數調用的時候加載)this
取值順序:在局部調用:局部命名空間===>全局命名空間===>內置命名空間
在全局調用:全局命名空間===>內置命名空間
使用:
全局不能使用局部的
局部能夠使用全局的
綜上所述,在找尋變量時,從小範圍,一層一層到大範圍去找尋。
3、做用域
一、做用域就是做用範圍
二、命名空間和做用域是分不開的
三、做用域分爲兩種:
全局做用域:全局命名空間與內置命名空間都屬於全局範圍
在整個文件的任意位置都能被引用,全局有效
局部做用域:局部命名空間,只能在局部範圍內生效
四、站在全局看:
使用命名空間的時候,若是有全局命名空間,用全局命名空間
若是沒有全局命名空間,用局部命名空間
五、做用域:爲了函數內的變量不會影響到全局
六、globals和locals方法(站在全局看globals is locals)
1 name1 = 'wusir'
2 def func1(): 3 name2 = 'laonanhai'
4 print(globals()) # 打印全局變量 5 print(locals()) # 打印局部變量 6 func1() 7 # 輸出結果: 8 ''' 9 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000028AFAABC128>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/benjamin/python自動化21期/day3/06 函數的進階.py', '__cached__': None, 'name1': 'wusir', 'func1': <function func1 at 0x0000028AF8EB2F28>} 10 {'name2': 'laonanhai'} 11 '''
4、global關鍵字、nonlocal關鍵字
global:
一、聲明一個全局變量
二、更改一個全局變量
1 # 1、聲明一個全局變量 2 def func1(): 3 global name 4 name = 'alex'
5 return 6 func1() 7 print(name) 8
9 # 2、更改一個全局變量 10 name = 'wusir'
11 def func1(): 12 global name 13 name = 'alex'
14 return 15 func1() 16 print(name)
ps:對可變數據類型(list,dict,set)能夠直接引用不用經過global
1 # 對於可變數據類型的應用舉例 2 li = [1,2,3] 3 dic = {'a':'b'} 4
5 def change(): 6 li.append('a') 7 dic['q'] = 'g'
8 print(dic) 9 print(li) 10 change() 11 print(li) 12 print(dic)
nonlocal:
一、不能修改全局變量
二、在局部做用域中,對父級做用域(或者更外層做用域,非全局做用域)的變量進行引用和修改,而且引用的哪層,從那層及如下此變量所有發生改變。
1 def func1(): 2 name1 = 'alex'
3 print('+',name1) 4 def inner(): 5 nonlocal name1 6 name1= 'wusir'
7 print('*',name1) 8 def inner1(): 9 pass 10 inner() 11 print('%',name1) 12 func1() 13 # 輸出結果: 14 ''' 15 + alex 16 * wusir 17 % wusir 18 '''
1 def add_b(): 2 b = 42
3 def do_global(): 4 b = 10
5 print(b) 6 def dd_nonlocal(): 7 nonlocal b 8 b = b + 20
9 print(b) 10 dd_nonlocal() 11 print(b) 12 do_global() 13 print(b) 14 add_b()
5、函數名的本質
函數名本質上就是函數的內存地址。
一、能夠被引用
1 def func(): 2 print('in func') 3
4 f = func 5 print(f)
二、能夠被看成容器類型的元素
1 def f1(): 2 print('f1') 3
4
5 def f2(): 6 print('f2') 7
8
9 def f3(): 10 print('f3') 11
12 l = [f1,f2,f3] 13 d = {'f1':f1,'f2':f2,'f3':f3} 14 #調用 15 l[0]() 16 d['f2']()
三、能夠看成函數的參數和返回值
1 def f1(): 2 print('f1') 3
4 def func1(argv): 5 argv() 6 return argv 7
8 f = func1(f1) 9 f()
第一類對象(first-class object)指
1.可在運行期建立
2.可用做函數參數或返回值
3.可存入變量的實體。
*不明白?那就記住一句話,就當普通變量用
6、閉包
1 def func(): 2 name = 'gaodong'
3 def inner(): 4 print(name) 5 inner() 6 wrapper()
閉包函數:
內層函數對外層函數非全局變量的引用,叫作閉包。
函數內部定義的函數稱爲內部函數。
閉包的好處:若是python檢測到閉包,他有一個機制,你的局部做用域不會隨着函數的結束而結束。
1 name = 'alex'
2 def wrapper(argv): 3 def inner(): 4 print(argv) 5 inner() 6 print(inner.__closure__) # cell 7 wrapper(name)
判斷閉包函數的方法__closure__
1 #輸出的__closure__有cell元素 :是閉包函數 2 def func(): 3 name = 'eva'
4 def inner(): 5 print(name) 6 print(inner.__closure__) 7 return inner 8
9 f = func() 10 f() 11
12 #輸出的__closure__爲None :不是閉包函數 13 name = 'egon'
14 def func2(): 15 def inner(): 16 print(name) 17 print(inner.__closure__) 18 return inner 19
20 f2 = func2() 21 f2()
1 def wrapper(): 2 money = 1000
3 def func(): 4 name = 'eva'
5 def inner(): 6 print(name,money) 7 return inner 8 return func 9
10 f = wrapper() 11 i = f() 12 i()
1 from urllib.request import urlopen 2
3 def index(): 4 url = "http://www.xiaohua100.cn/index.html"
5 def get(): 6 return urlopen(url).read() 7 return get 8
9 xiaohua = index() 10 content = xiaohua() 11 print(content)
7、總結
# 閉包和裝飾器
# 閉包的定義 : 內部函數引用外部函數的變量
# 閉包的應用 :裝飾器
練習:
1 def wrapper(): 2 def inner(): 3 name1 = 'alex'
4 print(name1) 5 inner() 6 wrapper() 7
8 def wrapper(): 9 def inner(): 10 name1 = 'alex'
11 print(name1) 12 return inner 13 ret = wrapper() # inner 14 ret()