從 python 解釋器開始執行以後,就在內存中開闢了一個空間,每當遇到一個變量的時候,就把變量名和值之間的對應關係記錄下來。可是 當遇到函數定義的時候解釋器只是象徵性的將函數名讀入內存,表示知道這個函數的存在了,至於函數內部的變量和邏輯解釋器根本不關心。等執行到函數調用的時候,python解釋器會再開闢一塊內存來存儲這個函數裏的內容,這個時候,才關注函數裏面有哪些變量,而函數中的變量會存儲在新開闢出來的內存中。python
函數中的變量只能在函數的內部使用,而且會隨着函數執行完畢,這塊內存中的全部內容也會被清空。閉包
咱們給這個‘存放名字與值的關係’的空間起了一個名字————叫作命名空間ide
代碼在運行伊始,建立的存儲‘變量名與值的關係’的空間叫作 全局命名空間,在函數的運行中開闢的臨時的空間叫作 局部命名空間。函數
命名空間的本質:存放名字與值的綁定關係測試
命名空間有三種:
內置命名空間
內置命名空間中存放了python解釋器爲咱們提供的名字:input,print,str,list,tuple...它們都是咱們熟悉的,拿過來就能夠用的方法。
全局命名空間
在python文件中,頂頭命名的變量名字,都包含在全局命名空間中
局部命名空間
函數和類中的都在局部命名空間中,且每一個局部命名空間是相互獨立的spa
三種命名空間之間的加載與取值順序:
加載順序:內置命名空間(程序運行前加載)->全局命名空間(程序運行中:從上到下加載)->局部命名空間(程序運行中:調用時才加載)
取值:
在局部調用:局部命名空間->全局命名空間->內置命名空間。必須遵照從內向外找,直到內置空間中若是也沒有,則報錯;3d
做用域就是做用範圍,按照生效範圍能夠分爲全局做用域和局部做用域。
全局做用域:包含內置名稱空間、全局名稱空間,在整個文件的任意位置都能被引用、全局有效
局部做用域:局部名稱空間,只能在局部範圍內生效code
globals 和 locals 使用方法對象
print(globals()) # 打印全局命名空間中的變量 print(locals()) # 在全局中打印全局命名空間中的變量,在局部打印局部命名空間中的變量 print(globals() == locals()) # 當 globals() 和 locals() 都在全局做用域中,打印的結果同樣 # 執行結果: # ...... # True
def func(): a = 1 print(globals()) # 打印全局命名空間中的變量 print(locals()) # 只會打印局部命名空間中的變量,{'a': 1} func() global 關鍵字的使用 a = 10 def func(): global a # 獲取全局空間中的變量 a = 20 # 修改變量a print(a) # 打印全局變量中的a func() print(a) # 打印修改後的變量a # 執行結果: # 10 # 20
def f1(): print('in f1') def f2(): print('in f2') f2() f1() # 執行結果: # in f1 # in f2
函數運行流程:blog
def f1(): def f2(): def f3(): print('in f3') print('in f2') f3() print('in f1') f2() f1() # 執行結果: # in f1 # in f2 # in f3
函數運行流程:
函數的做用域鏈
def f1(): a = 1 def f2(): print(a) f2() f1()
函數運行流程:
def f1(): a = 1 def f2(): def f3(): print(a) f3() f2() f1() # 執行結果: # 1
函數運行流程:
nolocal 關鍵字
1. 外部必須有這個變量
2. 在內部函數聲明 nonlocal 變量以前不能再出現同名變量
3. 內部修改這個變量若是想在外部有這個變量的第一層函數中生效
def f1(): a = 1 def f2(): nonlocal a a = 2 f2() print('a in f1:', a) f1() # 運行結果: # a in f1: 2
函數運行流程:
函數的本質
在python中一切皆對象,函數名本質上就是函數的內存地址
1. 能夠被引用
def func(): print('hello world') f = func f() # 執行結果: # hello world
2. 能夠被看成容器類型的元素
def f1(): print('func: f1') def f2(): print('func: f2') def f3(): print('func: f3') l = [f1, f2, f3] for i in l: i() # 執行結果: # func: f1 # func: f2 # func: f3
3. 能夠看成函數的參數和返回值
def f(): print('func: f') def func(f): print('func: func') return f c = func(f) c() # 執行結果: # func: func # func: f
函數運行流程:
閉包函數包含對外部做用域而非全局做用域名字的引用,該內部函數稱爲閉包函數。
閉包必須知足如下兩點:
1. 嵌套函數:定義在內部的函數沒法直接在全局被調用
2. 內部函數調用外部函數的變量
一個閉包函數最經常使用的用法:
def func(): name = 'xiaofei' def inner(): print(name) return inner f = func() f() # 執行結果: # xiaofei
函數運行流程:
練習題:
請編寫代碼經過以下測試結果:
# 測試: counterA = createCounter() print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5 counterB = createCounter() if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]: print('測試經過!') else: print('測試失敗!')
def createCounter(): n = 0 def counter(): nonlocal n # nonlocal關鍵字是獲取局部變量n n += 1 # 修改局部變量 n return n return counter