[ python ] 函數進階

 命名空間

從 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
使用說明1
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
使用說明2

 

 

函數的嵌套和做用域鏈

 

def f1():
    print('in f1')
    def f2():
        print('in f2')
    f2()

f1()

# 執行結果:
# in f1
# in f2
函數嵌套實例1

 

函數運行流程: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
嵌套函數實例2

 

 

函數運行流程:

 

 

函數的做用域鏈

 

def f1():
    a = 1
    def f2():
        print(a)

    f2()

f1()
實例1

 

函數運行流程:

 

def f1():
    a = 1
    def f2():
        def f3():
            print(a)

        f3()
    f2()

f1()

# 執行結果:
# 1
實例2

 

 

函數運行流程:

 

 

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
實例1

 

函數運行流程:

 

函數的本質
    在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
練習題答案
相關文章
相關標籤/搜索