python開發第四篇–函式

禁止進入i發表於2019-02-16

名稱空間與作用域

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.在區域性作用域中,對父級作用域(或者更外層作用域非全域性作用域)的變數進行引用和修改,並且引用的哪層,從那層及以下此變數全部發生改變。

注:對於可變的資料型別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
# 裝飾器 本質就是閉包
# 裝飾器根本作用:在不影響原函式執行的基礎上,增加一些額外的功能登入認證,列印日誌等等。

內褲可以用來遮羞,但是到了冬天它沒法為我們防風禦寒,聰明的人們發明了長褲,有了長褲後寶寶再也不冷了,裝飾器就像我們這裡說的長褲,在不影響內褲作用的前提下,給我們的身子提供了保暖的功效。

相關文章