Python之函式式程式設計(二)

2021-10-06 12:54:58 字數 4133 閱讀 6940

##要點

外部巢狀作用域

什麼是閉包?

什麼是函式裝飾器?

函式裝飾器的實現原理?

裝飾器中關於函式引數的體現

外部巢狀作用域

通過對python函式作用域的學習,可以了解python函式中擁有四大變數並通過legb法則負責不同範圍的作用域,分別為區域性作用域(local)、外部巢狀作用域(enclsing)、全域性作用域(global)和內建模組作用域(builtin)。而需要注意的是外部巢狀作用主要存在函式之間,用作函式巢狀時對引數的修改,關鍵字為nonlocal。**如下:

def

func01()

:print

("func01執行嘍"

) a =

100# 區域性變數 外部巢狀變數

deffunc02()

:print

("func02又執行嘍"

)# 如果修改外部巢狀變數,使用nonlocal修飾

nonlocal a

a =200 func02(

)print

(a)# 外部巢狀函式

func01(

)

從**上可以看到,外部巢狀變數主要負責對外層函式的區域性變數進行修改。由此也可以看出作用域之間是相對而言,不過這個不是我們今天討論的重點。如果沒有關鍵字nonlocal,內部函式只能訪問外部函式的引數,但是不能對其進行修改。在接下來的閉包介紹中,也就用到了這一點。

什麼是閉包?

閉包是由函式及其相關的引用環境組合而成的實體。其內部函式可以使用外部變數,也正是這有原因,外部變數可以一直存在於記憶體中,不會在呼叫結束後進行釋放。

閉包三要素

– 必須有乙個內嵌函式。

– 內嵌函式必須引用外部函式中變數。

– 外部函式返回值必須是內嵌函式。

閉包語法

– 定義:

def 外部函式名(引數):

外部變數

def 內部函式名(引數):

使用外部變數

return 內部函式名

– 呼叫:

變數 = 外部函式名(引數)

變數(引數)

def

func01()

: a =

100def

func02()

:print

(a)return func02 # 不是在此呼叫func02

# 呼叫外部函式,得到的是內部函式

result = func01(

)result(

)# 100

result(

)# 100

result(

)# 100

可通過以上**進行解讀,以上**通過呼叫func01函式,開始執行func01。並返回func02記憶體位址,賦值給result,因此變數result中儲存的是func02的記憶體位址,在此過程中,是不會執行巢狀函式func01的,只是將其**放在記憶體開闢的**區中。

只有當呼叫result函式時,才會去執行func02()函式,不斷呼叫,也會不斷執行func02()函式。在這一過程中,也正是體現了閉包的三大要素。

閉包的作用

閉包其作用在於保留外部函式的棧幀,以為內部函式提供引數訪問;而在實際的使用中,儲存耗費記憶體來儲存外函式的棧幀,就是為了處理一些連續的邏輯計算的場景【也可以理解為仍然能夠保持住當前的執行環境】。如下**展示:

def

give_gife_money

(money)

:print

("獲得了%d元壓歲錢"

% money)

defchild_buy

(target, price)

:nonlocal money

money -= price

print

("花了%d元購買了%s,還剩下%d元"

%(price, target, money)

)return child_buy

# 獲得了1000元壓歲錢

action = give_gife_money(

1000

)action(

"遙控飛機"

,300

)action(

"存錢罐",20

)action(

"口紅"

,400

)action(

"小人書"

,200

)

在不斷呼叫action方法時,實際上也在不斷的呼叫child_buy()方法,即,不斷的通過邏輯計算訪問外部的區域性變數。這正是函式式程式設計中閉包的強大之處。

什麼是函式裝飾器?

函式裝飾器是函式式程式設計中一大亮點,也是乙個比較難以理解的技能之一。函式裝飾器是在***不改變原函式的呼叫***以及內部**情況下,為其***新增新功能的函式***。

語法

定義:def 函式裝飾器名稱(func):

def 內嵌函式(*args, **kwargs):

需要新增的新功能

return func(*args, **kwargs)

return內嵌函式

原函式 = 內嵌函式

呼叫:@ 函式裝飾器名稱

def 原函式名稱(引數):

函式體原函式(引數)

函式裝飾器的實現原理

函式裝飾器的實現主要還是依賴於閉包的設計思想,外部函式負責對呼叫者進行攔截呼叫新功能,內部函式則負責將新舊功能進行包裹。可通過以下**進行解讀:

def

new_func

(func)

:# 外函式負責攔截

def():

# 內函式負責包裹

print

("驗證許可權"

)# 函式內部的新功能

func(

)# 需要呼叫舊功能

@new_func # enter_background = new_func(enter_background)

defenter_background()

:print

("進入後台"

)# 測試**

enter_background(

)enter_background(

)

裝飾器中關於函式引數的體現

在呼叫函式時,實際已經被***攔截下來,因此傳參是針對外部函式而言,由於呼叫函式時實參的數量和型別不一致,可以使用*args和**kwargs進行接收,並以此在內部函式返回值中,呼叫舊函式的形參。**如下:

def

verif_permissions

(func)

:def

(*args,

**kwargs)

:print

("驗證許可權"

)return func(

*args,

**kwargs)

@verif_permissions

defenter_background

(login,pwd)

:print

("進入後台"

)# 呼叫

enter_background(

"lsw"

,123456

)enter_background(

"lsw"

,123456

,"hhhhhh"

)

根據剛剛介紹的裝飾器原理可以了解,呼叫者中的實參在傳遞給enter_background()方法時,實際已經被外部函式進行了攔截,因此實際是傳給內部函式的,由於內部函式不知道以什麼型別的形參進行接收,因此通過星號元組形參和雙星字典形參來接收呼叫者傳入的位置實參和命名關鍵字實參,而後傳給enter_background,並將其返回值作為內部函式的返回值返回。

函式裝飾器還仍然在學習階段,還希望各位小夥伴來給出補充意見,感謝!

Python之 函式式程式設計

f lambda x x 2 定義函式f x x 2 g lambda x,y x y 定義函式g x,y x y 假設有乙個列表a 1,2,3 要給列表中的每個元素都加2得到乙個新列表,利用列表解析,我們可以這樣寫 b i 2 for i in a 利用map函式我們可以這樣寫 b map lam...

Python之函式式程式設計

1 map map 函式接收兩個引數,乙個是函式,乙個是iterable,map將傳入的函式依次作用到序列的每個元素,並把結果作為新的iterator返回。def f x return x x r map f,1,2,3,4,5,6,7,8,9 print list r 1,4,9,16,25,36...

python高階之函式式程式設計

函式式程式設計不是函式程式設計。函式 function 編寫函式以及呼叫函式 函式式 fuctional 是一種程式設計正規化,是抽象於計算的程式設計模式 函式式程式設計的特點 1.把計算視為函式而非指令 2.純函式式程式設計 不需要變數,測試簡單,還沒有 3.支援高階函式,簡介 而python 支...