1. 程式人生 > >Python函數2

Python函數2

對應關系 順序執行 開始 NPU 賦值 沒有 關註 輸出 地址

一、命名空間:

什麽是命名空間:

  --> Python代碼在執行的過程中從上到下順序執行,

  --> 從python解釋器開始執行之後,就在內存中開辟了一個空間。

  --> 每當遇到一個變量的時候,就把變量名和值之間的對應關系記錄下來。

  --> 但是,當遇到函數的時候,Python解釋器只是將函數名稱讀入內存,並且知道這個函數已經存在了,此時,函數內部的變量和邏輯關系解釋器根本就不關心,並沒有執行函數內部的代碼

  --> 等到執行函數的調用的時候,Python解釋器才會在內存中再開辟一塊兒空間,來存儲函數裏面的代碼內容,這個時候,才會關註函數內部有哪些變量。函數內部的變量存儲在新開辟的空間中,只能供函數內部使用,等函數執行完畢,這塊兒內存空間中所有內容都會被清空。

  --> 我們給這個“存放名字與值的關系”的空間起了一個名字——叫做命名空間

命名空間分為三種:全局命名空間,局部命名空間,內置命名空間。

1.首先先說下內置命名空間:裏面包含了Python解釋器為我們提供的一些名字。比如:input,print,list,tuple等等。我們直接拿過來用就可以。

2.全局命名空間:代碼在運行伊始,創建的存儲“變量名與值的關系”的空間叫做全局命名空間。

3.局部命名空間:在函數的運行中開辟的臨時的空間叫做局部命名空間。

命名空間的加載順序:內置命名空間(程序運行前加載)->全局命名空間(程序運行中:從上到下加載)->局部命名空間(程序運行中:調用時才加載)

關於作用域:作用域就是作用範圍,按照生效範圍可以分為全局作用域和局部作用域。

  全局作用域:包含內置命名空間和全局作用空間,在整個文件的任意位置都能被引用、全局有效

  局部作用域:局部名稱空間,只能在局部範圍內使用

關於global關鍵字

來看一段代碼:

a = 1
def func():
    a = 20
print(a)
func()
print(a)

上面的代碼打印結果

1
1

第一個 print(a)在調用函數之前打印 a 的值,打印 1 ,後面調用函數,在函數內部,明明已經修改了 a的值,後面打印 還是打印 1 。其實,第一個 a = 1.這個a 是全局命名空間。在函數內部 a = 20 ,這個a是局部命名空間,如果想在函數內部,對全局變量的值做修改,可以使用關鍵字 global

a = 1

def func():
    global a
    a = 20

print(a)
func()
print(a)

這次的打印結果

1
20

二、關於函數的探討

先看一段代碼:

def func(): # 定義一個函數
    pass

f = func # 將函數名稱賦值給一個變量

print(func) # 打印函數名稱
print(f) # 打印變量 f

執行結果

<function func at 0x000000000050C1E0> # 翻譯結果:0x000000000050c1e0處的函數func
<function func at 0x000000000050C1E0>

從結果中可以看出:函數名稱實際上存放的是這個函數的一個內存地址,另外,函數名也可以賦值給一個變量,其實函數名也是一個變量

既然函數名本質上其實就是一個變量,那麽,函數名也就可以作為容器中的一個元素。如:

def func1():
    pass

def func2():
    pass

def func3():
    pass

list_func = [func1,func2,func3]
for l_func in list_func:
    print(l_func)

打印結果

<function func1 at 0x00000000003DC1E0>
<function func2 at 0x0000000002718510>
<function func3 at 0x0000000002718598>

也可以當做函數的參數以及返回值

def outer():
    name = jack
    def inner():
        print(name)
    return inner

outer()

三、閉包:內部函數包含對外部作用域而非全劇作用域名字的引用,該內部函數稱為閉包函數

來看一段代碼

def outer(x):
    def inner(y):
        return x + y
    print(inner.__closure__)  # 使用__closure__ 判斷是否為閉包,如果輸出包含cell 則是閉包。如果輸出為None 則不是閉包
    return inner

f = outer(9)
print(type(f)) # 打印f的類型
print(f.__name__) # 輸出 f 的名字

輸出結果

(<cell at 0x00000000021DB858: int object at 0x000007FEDFC5D520>,)
<class function>
inner

結合這段簡單的代碼和定義來說明閉包:
如果在一個內部函數裏:inner(y)就是這個內部函數,對外部作用域(但不是在全局作用域)的變量進行引用:x就是被引用的變量(x在外部作用域outer裏面,但是不是全局作用域),name這個內部函數就是一個閉包

使用閉包的註意事項:

在閉包中,是不能修改外部作用域的變量的值

def outer():
    a = 0
    def inner():
        a = 1
        print(a)
    print(a)
    inner()
    return inner

outer()

打印結果

0
1

另外需要註意的一點是:閉包不要引用任何的循環變量,或者後續會發生變化的變量

Python函數2