名稱空間與作用域
1.變數儲存在一個記憶體空間中
2.當程式執行的時候程式碼從上到下依次執行,它會將變數與值的關係儲存在一個空間中,這個空間叫名稱空間,名稱空間,全域性名稱空間
3.當程式遇到函式時,它會將函式名存在記憶體中,函式體漠不關心
4.當程式執行的時候,記憶體會臨時開闢一個空間,存放函式體裡的程式碼(變數,程式碼等)
5.函式外面訪問不到臨時空間的內容,隨著函式執行完畢,臨時名稱空間會被釋放掉,向這個臨時開闢的空間也叫臨時名稱空間,也叫區域性名稱空間
- python名稱空間分為三種:
1.內建名稱空間
2.全域性名稱空間
3.區域性名稱空間 -
按照作用域分為兩種:
-
全域性作用域
1.內建名稱空間 2.全域性名稱空間
-
區域性作用域
1.區域性名稱空間
-
- 載入順序
內建名稱空間—全域性名稱空間(當程式執行時)—區域性名稱空間(函式呼叫時) -
取值順序
區域性名稱空間(函式呼叫時)—全域性名稱空間(當程式執行時)—內建名稱空間
注:取值順序是單向不可逆的1.取值又叫引用,區域性名稱空間可以臨時像全域性名稱空間引用,但是無法修改 2.取值是從小到大取值LEGB - L=最裡層的區域性作用域 - E=父親級別的區域性作用域 - G=全域性作用域中的全域性名稱空間 - B=全域性作用域中的內建名稱空間
-
內建函式globals和locals的方法:
-
globles
globales返回一個字典,字典裡的內容是全域性名稱空間的內容
-
locals
locals返回一個字典,當前位置的所有變數(看locals的位置是否在函式體裡還是在全域性裡)
-
#1.
print(globals())
print(locals())
#列印結果:
{`__name__`: `__main__`, `__doc__`: None, `__package__`: None, `__loader__`: <_frozen_importlib_external.SourceFileLoader object at 0x004DB4B0>, `__spec__`: None, `__annotations__`: {}, `__builtins__`: <module `builtins` (built-in)>, `__file__`: `E:/python/day04/1.py`, `__cached__`: None}
{`__name__`: `__main__`, `__doc__`: None, `__package__`: None, `__loader__`: <_frozen_importlib_external.SourceFileLoader object at 0x004DB4B0>, `__spec__`: None, `__annotations__`: {}, `__builtins__`: <module `builtins` (built-in)>, `__file__`: `E:/python/day04/1.py`, `__cached__`: None}
#2.
def func():
a = 12
b = 20
print(locals())
print(globals())
func()
#列印結果:
{`b`: 20, `a`: 12}
{`__name__`: `__main__`, `__doc__`: None, `__package__`: None, `__loader__`: <_frozen_importlib_external.SourceFileLoader object at 0x0044B4B0>, `__spec__`: None, `__annotations__`: {}, `__builtins__`: <module `builtins` (built-in)>, `__file__`: `E:/python/day04/1.py`, `__cached__`: None, `func`: <function func at 0x0040B660>}
-
關鍵字global和nonlocal的方法:
- global
1.global可以引用全域性變數,並且改變全域性變數
2.在區域性作用域宣告一個全域性變數 - nonlocal
1.不能操作全域性變數
2.在區域性作用域中,對父級作用域(或者更外層作用域非全域性作用域)的變數進行引用和修改,並且引用的哪層,從那層及以下此變數全部發生改變。
- global
注:對於可變的資料型別list,dict,set,不用引用global,nonlocal
注:如果預設引數是一個可變的資料型別,那麼他在記憶體中永遠是一個。
#1.第一種情況:
def extendList(val,list=[]):
list.append(val)
return list
list1 = extendList(10)
print(`list1=%s`%list1) # [10,]
list2 = extendList(123,[])
print(`list2=%s`%list2) # [123,]
list3 = extendList(`a`)
print(`list3=%s`%list3) #[10,`a`]
列印結果為:
list1=[10]
list2=[123]
list3=[10, `a`]
#2.第二種:
def extendList(val,list=[]):
list.append(val)
return list
list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList(`a`)
print(`list1=%s`%list1)
print(`list2=%s`%list2)
print(`list3=%s`%list3)
列印結果為:
list1=[10, `a`]
list2=[123]
list3=[10, `a`]
因為:如果預設引數是一個可變的資料型別,那麼他在記憶體中永遠是一個。
1.global例項:
def func():
global a
a = 3
func()
print(a)
#列印結果為:3
count = 1
def search():
global count
count = 2
search()
print(count)
#列印結果為2
2.nonloacl例項:
def add_b():
b = 42
def do_global():
b = 10
print(b)
def dd_nonlocal():
nonlocal b
b = b + 20
print(b)
dd_nonlocal() #30
print(b) #30
do_global() #10
print(b)
add_b()
#列印結果為:
10
30
30
42
函式
- 函式的巢狀與呼叫:
#函式的巢狀
def max2(x,y):
m = x if x>y else y
return m
def max4(a,b,c,d):
res1 = max2(a,b)
res2 = max2(res1,c)
res3 = max2(res2,d)
return res3
#函式的呼叫
max4(1,2,3,4)
- 函式名的本質
1.列印函式名
def func():
print(`in func`)
f = func
print(f)
#列印結果為:<function func at 0x0020B660>
為一塊記憶體地址
2.函式名可以作為容器類資料的元素
def func1():
print(111)
def func2():
print(222)
def func3():
print(333)
l1 = [func1, func2, func3]
for i in l1:
i()
#列印結果為:
111
222
333
3.函式名可以作為函式的引數
def func1():
print(111)
def func2(x):
print(x)
x()
print(222)
func2(func1)
#列印結果為:
<function func1 at 0x0021B660>
111
222
4.函式名可以作為函式的返回值
def func1():
return 111
def func2(x): # x = func1
print(222)
return x
ret = func2(func1) # func1
print(ret())
print(ret)
#列印結果為:
222
111
<function func1 at 0x002BB660>
-
總結:
函式名的應用,第一類物件- 函式名列印的出來的是個記憶體地址,加()號就可以執行 - 函式名可以作為容器型別內的元素 - 函式名可以作為傳遞的引數 - 函式名可以作為函式的返回值,return把值給函式的執行者
-
閉包函式
- 內層函式對外層函式非全域性變數的引用,就叫做閉包 - 判斷是否是閉包:__closure__ - 如果python直譯器遇到了閉包,他有個機制,這個閉包不會隨著函式的結束而釋放 - 裝飾器@語法糖,裝飾器放在需要裝飾的函式的上邊,利用的就是閉包函式
裝飾器:
#測試func1函式的執行時間
def timmer(f):
def inner(*args,**kwargs):
start_time = time.time()
ret = f(*args,**kwargs)
end_time = time.time()
print(`此函式的執行效率%s` % (end_time - start_time))
return ret
return inner
@timmer
def func1():
time.sleep(0.3)
print(`非常複雜......`)
func1()
#格式為:
def wrapper(f):
def inner(*args,**kwargs):
"""被裝飾函式執行之前的操作"""
ret = f(*args,**kwargs)
"""被裝飾函式執行之後的操作"""
return ret
return inner
# 裝飾器 本質就是閉包
# 裝飾器根本作用:在不影響原函式執行的基礎上,增加一些額外的功能登入認證,列印日誌等等。
內褲可以用來遮羞,但是到了冬天它沒法為我們防風禦寒,聰明的人們發明了長褲,有了長褲後寶寶再也不冷了,裝飾器就像我們這裡說的長褲,在不影響內褲作用的前提下,給我們的身子提供了保暖的功效。