命名空間分爲三種:python
內置命名空間:閉包
是python解釋器一啓動就可使用的名字,存儲在內置命名空間中,啓動解釋器的時候被加載進內存裏。好比list,tuple等等。函數
全局命名空間:ui
是在程序從上到下被執行的過程當中依次加載進內存的,放置了咱們設置的全部變量名和函數名。url
1 a = 1 2 def func(): 3 print(a) 4 fun()
局部命名空間:spa
就是函數內部定義的名字,當調用函數的時候 纔會產生這個名稱空間 隨着函數執行的結束 這個命名空間就又消失了。code
1 def func(): 2 a = 1 3 print(a) 4 func()
在局部:可使用全局、內置命名空間中的名字。blog
在全局:可使用內置命名空間中的名字,可是不能用局部命名空間中的名字。事件
在內置:不能使用局部和全局的名字的。內存
注意如下幾點:
(1)在正常狀況下,直接使用內置的名字
(2)當咱們在全局定義了和內置名字空間中同名的名字時,會使用全局的名字
(3)當在一個函數內,有我要使用的變量名,我就回去使用它,沒有的話,我就會向上級去尋找,找到了就用,找不到就繼續尋找,若是還找不到,就報錯
1 def input(): 2 print('input') 3 def func(): 4 input() 5 func() 6 # result:input
(4)多個函數應該擁有多個獨立的局部名字空間,不互相共享,即在函數A中不能使用函數B的局部變量
(5)函數名()---函數的調用 等價於 函數的內存地址()---函數的調用
1 def input(): 2 print('input') 3 def func(): 4 print(input)# 這裏輸出的是函數的內存地址---<function input at 0x000001D05CEEC2F0> 5 func()
全局做用域 —— 做用在全局 —— 內置和全局名字空間中的名字都屬於全局做用域 ——用globals()能夠打印出來
局部做用域 —— 做用在局部 —— 函數(局部名字空間中的名字屬於局部做用域) ——用locals()能夠打印出來
1 a = 1 2 b = 2 3 def func(): 4 x = 'aaa' 5 y = 'bbb' 6 print(locals()) 7 print(globals()) 8 func() 9 print(globals()) 10 print(locals()) #本地的 11 # result: 12 # {'x': 'aaa', 'y': 'bbb'} 13 # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000013D05871CF8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python/PyChram/WorkPlace/day01/Demo.py', '__cached__': None, 'input': <function input at 0x0000013D058AC2F0>, 'func': <function func at 0x0000013D05A5A8C8>, 'a': 1, 'b': 2} 14 # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000013D05871CF8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python/PyChram/WorkPlace/day01/Demo.py', '__cached__': None, 'input': <function input at 0x0000013D058AC2F0>, 'func': <function func at 0x0000013D05A5A8C8>, 'a': 1, 'b': 2} 15 # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000013D05871CF8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/Python/PyChram/WorkPlace/day01/Demo.py', '__cached__': None, 'input': <function input at 0x0000013D058AC2F0>, 'func': <function func at 0x0000013D05A5A8C8>, 'a': 1, 'b': 2}
能夠看到,內置函數中的locals打印的就是內置函數中定義的變量,而globals不論在哪裏都打印全局變量,至於函數外的locals,他會將globals看做是一個笨的的變量,因此他打印出來的也是全局的。總結以下:
(1)globals 永遠打印全局的名字
(2)locals輸出什麼,根據locals所在的位置
1 a = 1 2 def func(): 3 global a 4 a = 2 5 func() 6 print(a)
在上面代碼中,在函數外,如果想要打印出函數內的變量,只要在函數內對這個變量加上一個global就好了,可是通常不建議這麼作,由於別人看你的代碼時,只會看到你定義的全局變量a = 1,誰會看到你函數內又將他變成了a = 2呢,因此建議不要使用global。
1 def max(a,b): 2 return a if a>b else b 3 def the_max(x,y,z): #函數的嵌套調用 4 c = max(x,y) 5 return max(c,z) 6 print(the_max(1,2,3))
a = 1 def outer(): a = 1 def inner(): a = 2 def inner2(): nonlocal a #聲明瞭一個上面第一層局部變量 a += 1 #不可變數據類型的修改 inner2() print('##a## : ', a) inner() print('**a** : ',a) outer() print('全局 :',a) # result: # ##a## : 3 # **a** : 1 # 全局 : 1
這裏展現的是函數的嵌套定義,同時也展現了nonlocal的使用方法。
nonlocal可使內部函數使用外部函數的變量。它的使用規則是找到距離當前函數上面最近一個函數的變量。好比說,nonlocal a,那麼我在上面一個函數上找是否有a,有的話就用它,沒有的話就繼續找,直到有爲止。
nonlocal的聲明,當修改這個變量後,會影響到被找到的那個函數的變量,也就是說,若你在內部函數修改了外部變量,則外部變量也會被修改。
nonlocal只能做用於局部變量,不能做用於全局變量。
def func(): print(123) def wahaha(f): f() return f #函數名能夠做爲函數的返回值 qqxing = wahaha(func) # 函數名能夠做爲函數的參數 qqxing() # result: # 123 # 123
所謂閉包就是內部函數調用外部函數的變量。
def outer(): a = 1 def inner(): print(a)#調用的是外部函數的a,因此這是一個閉包 print(inner.__closure__) outer()#(<cell at 0x000001FAA0251918: int object at 0x00007FF96C376290>,)---在這裏打印出來了一個cell什麼的,就說明這個函數是閉包 print(outer.__closure__)#None---這裏輸出爲空,說明它不是一個閉包
閉包的經常使用形式:
在這裏說明一下閉包的好處,當使用閉包以後,我就不用每次都去聲明這個a變量,由於使用閉包以後,a就一直存在內存中,不會消失,即大大節省了時間。
def outer(): a = 1 def inner(): print(a) return inner inn = outer() inn()
閉包的簡單用處:
import urllib #模塊 from urllib.request import urlopen ret = urlopen('https://www.52pojie.cn/').read() print(ret)
上面代碼是獲取一個網頁的源碼。
from urllib.request import urlopen def get_url(): url = 'https://www.52pojie.cn/' def get(): ret = urlopen(url).read() print(ret) return get get_re = get_url() get_re()
使用閉包以後,我就不用每次都去聲明這個url了,由於他一直在內存中,節省了事件。