1. 程式人生 > >20181128(閉包函式,函式巢狀,名稱空間,作用域,裝飾器待補充)

20181128(閉包函式,函式巢狀,名稱空間,作用域,裝飾器待補充)

 

一、函式物件

在面向物件的程式設計中 一切皆物件

具體的體現:

1.函式可以被引用

def bar():
   print('from bar')

f=bar
f()
輸出結果為:
from bar

2.函式可以作為函式的引數

def bar():
   print('from bar')

def wrapper(func): #func=bar
   func() #bar()

wrapper(bar)
輸出結果為:
from bar

 

3.函式可以作為函式的返回值

def bar():
   print('from bar')

def foo(func):
   return func

f=foo(bar) #先執行這一句,得出f=bar
f()  #等同於bar()
輸出結果為:
from bar

 

4.可以被儲存到容器型別中

def get():
   print('from get')

def put():
   print('from put')

l=[get,put]
l[0]()
輸出結果為;
from get

#寫一個購物車,要求註冊登入

 

二、函式巢狀

1.巢狀呼叫:在一個函式中呼叫了另一個函式

def max2(x,y):
   if x > y:
       return x
   else:
       return y

def max3(x,y,z):
   res1=max2(x,y)  #因為max2函式有返回值,所以可以有等於
   res2=max2(res1,z)
   return res2  #等同於返回最大值

print(max3(11,199,2))
輸出結果為:
199

 

2.巢狀定義:在一個函式中,又定義了另一個函式。定義在函式內的函式,只能在函式內使用,外界不能訪問。

def func1():
   print('from func1')
   def func2():
       print('from func2')
   func2()  #呼叫func2()函式
   print(func2)    #輸出其記憶體地址,觀察輸出結果為(所在功能塊,變數所在空間(區域性變數?全域性變數?),記憶體地址)
func1()
輸出結果:
from func1
from func2
<function func1.<locals>.func2 at 0x00000207784F9B70>  


def func1():
   print('from func1')
   def func2():
       print('from func2')
   func2()  
   print(func2)  
func1()
print(func2())  #此處會報錯,因為定義在函式內的函式,只能在函式內使用,外界不能訪問。

3.函式的巢狀中:nonlocal a #宣告使用上一層的變數a,如果上一層沒有則找上上一層,但是不能尋找全域性變數。巢狀作用域(enclosing 作用域,外層非全域性作用域)中的變數。

a = 1
b = 2
def func1():
   a = 10
   def func2():
       b = 20
       def func3():
           nonlocal a,b
           print(a,b)
       func3()
   func2()
func1()
print(a,b)
輸出結果為:
10 20
1 2
a = 1
b = 2
def func1():
   a = 10
   def func2():
       def func3():
           nonlocal a,b
           print(a,b)  #此處的b只能取函式內變數的值,不能取全域性變數的值,因為上一句已經申明a,b只能修改獲取巢狀作用域內的變數。
       func3()
   func2()
func1()
輸出結果會報錯

如果修改為:
a = 1
b = 2
def func1():
   a = 10
   def func2():
       def func3():
           nonlocal a
           print(a,b)  #此時b可以取全域性變數
       func3()
   func2()
func1()
輸出結果為:
10 2

 

三、名稱空間:又名name space,是存放變數名和值繫結關係的地方。

名稱空間分為三類:

builtins:內建名稱空間,儲存直譯器自帶的一些名稱與值的對應關係(直譯器啟動時建立,關閉直譯器時銷燬)

globals:全域性名稱空間,又名模組名稱空間,在模組內定義的名稱(檔案級別的名字),除了內建的和函式內的,都在全域性中。(執行py檔案時建立全域性名稱空間,在檔案結束或者檔案執行期間被刪除則失效。)

locals:區域性名稱空間,只要是函式內的名稱就是區域性的,包括區域性變數和形參(函式呼叫時建立,函式執行完畢後銷燬)

不同變數的作用域不同就是由於這個變數所在的名稱空間決定的。

載入順序:

內建名稱空間---》全域性名稱空間----》區域性名稱空間

查詢順序:

區域性名稱空間 ---》全域性名稱空間----》內建名稱空間

細分之下有四種空間:

locals 函式內的名字空間,包括區域性變數和形參
enclosing 外部巢狀函式的名字空間
globals 全域性變數,函式定義所在模組的名字空間
builtins 內建模組的名字空間
查詢順序為LEGB,即
locals-->enclosing function-->globals-->_builtins_

 

四、作用域

域:指的是區域、範圍的意思

python中有兩種最基本的變數作用域:

區域性變數:

1.只能在函式內使用

2.呼叫函式時生效,呼叫結束失效

全域性變數:

1.在任何位置都能訪問到

2.該範圍內的名字會伴隨程式的整個生命週期

 

區域性變數:在函式內定義的變數名只能在函式內部引用,不能在函式外引用,這個變數的作用域是區域性的,也稱為區域性變數。一般來說,定義的變數如果是在函式體中第一次出現,就是區域性變數。

x = 50
def func(x):
   print(x)
   x = 2
   print(x)
func(x)
print(x)
輸出結果:   # 呼叫func()時建立了新的名稱空間,作用於func的程式碼塊
50
2
50

 

全域性變數:在函式體外,一段程式碼最開始賦值的變數可以被多個函式引用,這就是全域性變數。全域性變數可以在整個程式範圍內被引用。

num = 100
def func():
   num = 200
   print(num)
func()
print(num)
輸出結果:  #函式中使用某個變數時,如果該變數名既有全域性變數又有區域性變數,就預設使用區域性變數。在函式體中更改全域性變數的值不會影響全域性變數在其他函式或語句中的使用。
200
100

如何將區域性變數變更為全域性變數:

num = 100
print(num)
def func():
   global num  #在函式體中的變數前加關鍵字 global,函式呼叫結束後,在函式體外使用變數時,值變得和函                       數體中的值一樣
   num = 200
   num += 100
   print(num)

func()
print(num)
輸出結果:
100
300
300

 

globals() 檢視全域性作用域的內容

locals() 檢視區域性作用域的內容

五、閉包函式

閉包函式是一種函式,其中閉 指的是定義在函式內部的函式。

函式的作用域在定義的時候就固定了,與呼叫的位置沒有關係。

閉包的定義:如果在一個內部函式裡對外部函式(不是在全域性作用域)的變數進行引用,內部函式就認為是閉包。

閉包的意義:返回的函式物件,不僅僅是一個函式物件,在該函式外還包裹了一層作用域,這使得該函式無論在何處呼叫,都優先使用自己外層包裹的作用域。

什麼是閉包函式

①定義在另一個函式中的函式

②內部的函式中訪問了外部的名稱(不包含全域性的資料)

 

與普通函式的區別

①定義在另一個函式中的

②在內部的函式中使用了外部的名稱

def s(*args):
   def c():
       a=0
       for n in args:
           a=a+n
       return a
   return c
print(s(1,2,3,4))
c=s(1,2,3,4)
print(c())
輸出結果為:
<function s.<locals>.c at 0x000001F3D3469B70>
10

 

在返回內部函式時,不是單純的返回函式,還把函式中訪問到的區域性變數名稱一起打包了

 

閉包函式的模板:

def func1():

a = 1

def innner():

print(a)

return inner

func1()

 

 

六、裝飾器

對擴充套件開放,對修改封閉。即可以新增新功能,不能修改原始碼和呼叫方式

什麼是裝飾器:

給一個已有的物件,新增新的功能

裝飾器和閉包函式的關係:

裝飾器是一種設計程式碼的套路(在不修改原始碼和呼叫方法的情況下增加功能)

要完成裝飾器,就需要使用閉包函式。