日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python高阶函数闭包装饰器_Python自学从入门到就业之高阶函数、嵌套函数、闭包、装饰器...

發(fā)布時間:2024/9/27 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python高阶函数闭包装饰器_Python自学从入门到就业之高阶函数、嵌套函数、闭包、装饰器... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

高階函數(shù)

在Python中,函數(shù)其實也是一種數(shù)據(jù)類型。

def test():

return 'hello world'

print(type(test)) #

函數(shù)對應的數(shù)據(jù)類型是 function,可以把它當做是一種復雜的數(shù)據(jù)類型。

既然同樣都是一種數(shù)據(jù)類型,我們就可以把它當做數(shù)字或者字符串來處理。

定義一個變量指向函數(shù)

在Python中,我們還可以定義一個變量,讓它來指向一個函數(shù),相當于給函數(shù)起了一個別名。

def test():

return 'hello wrold'

fun = test # 定義了一個變量fun,讓它指向了 test 這個函數(shù)

print(fun()) # 使用fun()可以直接調(diào)用test這個函數(shù)

print(id(fun)) # 1819677672040

print(id(test)) # 1819677672040注意:在定義一個變量表示一個函數(shù)時,函數(shù)后面不能加括號!加括號表示的是調(diào)用這個函數(shù)。

def test():

return 'hello world'

result = test() # 這種寫法是調(diào)用test函數(shù),并把函數(shù)的返回值賦值給result變量

print(result()) # 這里會報錯 TypeError: 'str' object is not callable

fun = test # 這種寫法是給test函數(shù)起了一個別名,注意,這里的test后面不能加()

fun() # 可以使用別名調(diào)用這個函數(shù)

高階函數(shù)

既然變量可以指向函數(shù),函數(shù)的參數(shù)能接收變量,那么一個函數(shù)就可以接收另一個函數(shù)作為參數(shù),同樣,我們還可以把一個函數(shù)當做另一個函數(shù)的返回值。這種函數(shù)的使用方式我們稱之為高階函數(shù)。

函數(shù)做為另一個函數(shù)的參數(shù)

def test(age,action):

if age < 18:

print('您還沒滿十八歲,請退出')

action() # 把參數(shù)action直接當做一個函數(shù)來調(diào)用

def smoke():

print('我已經(jīng)年滿十八歲了,我想抽煙')

my_action = smoke # 定義一個變量my_action,讓它指向smoke函數(shù)

test(21, my_action) # 將my_action傳給 test 函數(shù)作為它的參數(shù)

test(21,smoke) # 還可以不再定義一個新的變量,直接傳入函數(shù)名

函數(shù)作為另一個函數(shù)的返回值

def test():

print('我是test函數(shù)里輸入的內(nèi)容')

def demo():

print('我是demo里輸入的內(nèi)容')

return test # test 函數(shù)作為demo函數(shù)的返回值

result = demo() # 我是demo里輸入的內(nèi)容 調(diào)用 demo 函數(shù),把demo函數(shù)的返回值賦值給 result

print(type(result)) # result 的類型是一個函數(shù)

result() # 我是demo里輸入的內(nèi)容 我是test函數(shù)里輸入的內(nèi)容 既然result是一個函數(shù),那么就可以直接使用() 調(diào)用這個函數(shù)

demo()() # 我是demo里輸入的內(nèi)容 我是test函數(shù)里輸入的內(nèi)容

函數(shù)嵌套

在函數(shù)里面還可以定義函數(shù),可以嵌套多層,執(zhí)行需要被調(diào)用。

def outer():

print('outer----hello')

def inner(): # inner這個函數(shù)是在outer函數(shù)內(nèi)部定義的

print('inner----hello')

inner() # inner函數(shù)只在outer函數(shù)內(nèi)部可見

outer()

# inner() 這里會報錯,在outer函數(shù)外部無法訪問到inner函數(shù)

閉包

函數(shù)只是一段可執(zhí)行代碼,編譯后就“固化”了,每個函數(shù)在內(nèi)存中只有一份實例,得到函數(shù)的入口點便可以執(zhí)行函數(shù)了。函數(shù)可以作為另一個函數(shù)的參數(shù)甚至返回值(高階函數(shù))。函數(shù)還可以嵌套定義,即在一個函數(shù)內(nèi)部可以定義另一個函數(shù),有了嵌套函數(shù)這種結(jié)構(gòu),便會產(chǎn)生閉包問題。

什么是閉包

閉包是由函數(shù)及其相關的引用環(huán)境組合而成的實體(即:閉包=函數(shù)塊+引用環(huán)境)。

def outer(n):

num = n

def inner():

return num+1

return inner

print(outer(3)()) # 4

print(outer(5)()) # 5

在這段程序中,函數(shù) inner 是函數(shù) outer 的內(nèi)嵌函數(shù),并且 inner 函數(shù)是outer函數(shù)的返回值。我們注意到一個問題:內(nèi)嵌函數(shù) inner 中引用到外層函數(shù)中的局部變量num,Python解釋器會這么處理這個問題呢? 先讓我們來看看這段代碼的運行結(jié)果,當我們調(diào)用分別由不同的參數(shù)調(diào)用 outer 函數(shù)得到的函數(shù)時,得到的結(jié)果是隔離的(相互不影響),也就是說每次調(diào)用outer函數(shù)后都將生成并保存一個新的局部變量num,這里outer函數(shù)返回的就是閉包。 如果在一個內(nèi)部函數(shù)里,對在外部作用域(但不是在全局作用域)的變量進行引用,那么內(nèi)部函數(shù)就被認為是閉包(closure).

修改外部變量的值

閉包里默認不能修改外部變量。

def outer(n):

num = n

def inner():

num = num + 1

return num

return inner

print(outer(1)())

上述代碼運行時會報錯!

UnboundLocalError: local variable 'num' referenced before assignment

原因分析

在python里,只要看到了賦值語句,就會認為賦值語句的左邊是一個局部變量。num = num + 1 這段代碼里,num 在=的左邊,python解析器會認為我們要修改inner函數(shù)里num這個局部變量,而這個變量使用之前是未聲明的,所以會報錯。

解決方案

我們分析過,報錯的原因在于當我們在閉包內(nèi)修改外部變量時,會被python解析器誤會為內(nèi)部函數(shù)的局部變量。所以,解決方案就在于,我們需要想辦法,讓解析器知道我們不是要修改局部變量,而是要修改外部變量。解決方法一:使用列表解決

def outer(n):

num = [n] # 定義一個變量num,將 n 包裹到一個列表里

def inner():

num[0] = num[0] + 1 # 從列表里取出并修改數(shù)據(jù)

return num[0]

return inner

print(outer(1)())解決方法二:python3后使用 nonlocal 關鍵字

def outer(n):

num = n

def inner():

nonlocal num # 修改前使用nonlocal關鍵字對 num 變量進行說明

num = num + 1

return num

return inner

print(outer(2)())

裝飾器

裝飾器是程序開發(fā)中經(jīng)常會用到的一個功能,用好了裝飾器,開發(fā)效率如虎添翼,所以這也是Python面試中必問的問題。但對于好多初次接觸這個知識的人來講,這個功能有點繞,自學時直接繞過去了,然后面試問到了就掛了,因為裝飾器是程序開發(fā)的基礎知識,這個都不會,別跟人家說你會Python, 看了下面的文章,保證你學會裝飾器。

1、先明白這段代碼

#### 第一波 ####

def foo():

print('foo')

foo # 表示是函數(shù)

foo() # 表示執(zhí)行foo函數(shù)

#### 第二波 ####

def foo():

print('foo')

foo = lambda x: x + 1

foo() # 執(zhí)行l(wèi)ambda表達式,而不再是原來的foo函數(shù),因為foo這個名字被重新指向了另外一個匿名函數(shù)

函數(shù)名僅僅是個變量,只不過指向了定義的函數(shù)而已,所以才能通過 函數(shù)名()調(diào)用,如果 函數(shù)名=xxx被修改了,那么當在執(zhí)行 函數(shù)名()時,調(diào)用的就不知之前的那個函數(shù)了

2、需求來了

初創(chuàng)公司有N個業(yè)務部門,基礎平臺部門負責提供底層的功能,如:數(shù)據(jù)庫操作、redis調(diào)用、監(jiān)控API等功能。業(yè)務部門使用基礎功能時,只需調(diào)用基礎平臺提供的功能即可。如下:

############### 基礎平臺提供的功能如下 ###############

def f1():

print('f1')

def f2():

print('f2')

def f3():

print('f3')

def f4():

print('f4')

############### 業(yè)務部門A 調(diào)用基礎平臺提供的功能 ###############

f1()

f2()

f3()

f4()

############### 業(yè)務部門B 調(diào)用基礎平臺提供的功能 ###############

f1()

f2()

f3()

f4()

目前公司有條不紊的進行著,但是,以前基礎平臺的開發(fā)人員在寫代碼時候沒有關注驗證相關的問題,即:基礎平臺的提供的功能可以被任何人使用。現(xiàn)在需要對基礎平臺的所有功能進行重構(gòu),為平臺提供的所有功能添加驗證機制,即:執(zhí)行功能前,先進行驗證。

老大把工作交給 Low B,他是這么做的:跟每個業(yè)務部門交涉,每個業(yè)務部門自己寫代碼,調(diào)用基礎平臺的功能之前先驗證。誒,這樣一來基礎平臺就不需要做任何修改了。太棒了,有充足的時間泡妹子...

當天Low B 被開除了…

老大把工作交給 Low BB,他是這么做的:

############### 基礎平臺提供的功能如下 ###############

def f1():

# 驗證1

# 驗證2

# 驗證3

print('f1')

def f2():

# 驗證1

# 驗證2

# 驗證3

print('f2')

def f3():

# 驗證1

# 驗證2

# 驗證3

print('f3')

def f4():

# 驗證1

# 驗證2

# 驗證3

print('f4')

############### 業(yè)務部門不變 ###############

### 業(yè)務部門A 調(diào)用基礎平臺提供的功能###

f1()

f2()

f3()

f4()

### 業(yè)務部門B 調(diào)用基礎平臺提供的功能 ###

f1()

f2()

f3()

f4()

過了一周 Low BB 被開除了…

老大把工作交給 Low BBB,他是這么做的:只對基礎平臺的代碼進行重構(gòu),其他業(yè)務部門無需做任何修改

############### 基礎平臺提供的功能如下 ###############

def check_login():

# 驗證1

# 驗證2

# 驗證3

pass

def f1():

check_login()

print('f1')

def f2():

check_login()

print('f2')

def f3():

check_login()

print('f3')

def f4():

check_login()

print('f4')

老大看了下Low BBB 的實現(xiàn),嘴角漏出了一絲的欣慰的笑,語重心長的跟Low BBB聊了個天:

老大說:

寫代碼要遵循開放封閉原則,雖然在這個原則是用的面向?qū)ο箝_發(fā),但是也適用于函數(shù)式編程,簡單來說,它規(guī)定已經(jīng)實現(xiàn)的功能代碼不允許被修改,但可以被擴展,即:封閉:已實現(xiàn)的功能代碼塊

開放:對擴展開發(fā)

如果將開放封閉原則應用在上述需求中,那么就不允許在函數(shù) f1 、f2、f3、f4的內(nèi)部進行修改代碼,老板就給了Low BBB一個實現(xiàn)方案:

def w1(func):

def inner():

# 驗證1

# 驗證2

# 驗證3

func()

return inner

@w1

def f1():

print('f1')

@w1

def f2():

print('f2')

@w1

def f3():

print('f3')

@w1

def f4():

print('f4')

對于上述代碼,也是僅僅對基礎平臺的代碼進行修改,就可以實現(xiàn)在其他人調(diào)用函數(shù) f1 f2 f3 f4 之前都進行【驗證】操作,并且其他業(yè)務部門無需做任何操作。

Low BBB心驚膽戰(zhàn)的問了下,這段代碼的內(nèi)部執(zhí)行原理是什么呢?

老大正要生氣,突然Low BBB的手機掉到地上,恰巧屏保就是Low BBB的女友照片,老大一看一緊一抖,喜笑顏開,決定和Low BBB交個好朋友。

詳細的開始講解了:

單獨以f1為例:

def w1(func):

def inner():

# 驗證1

# 驗證2

# 驗證3

func()

return inner

@w1

def f1():

print('f1')

python解釋器就會從上到下解釋代碼,步驟如下:def w1(func): ==>將w1函數(shù)加載到內(nèi)存

@w1

沒錯, 從表面上看解釋器僅僅會解釋這兩句代碼,因為函數(shù)在 沒有被調(diào)用之前其內(nèi)部代碼不會被執(zhí)行。

從表面上看解釋器著實會執(zhí)行這兩句,但是 @w1 這一句代碼里卻有大文章, @函數(shù)名 是python的一種語法糖。

上例@w1內(nèi)部會執(zhí)行一下操作:

執(zhí)行w1函數(shù)執(zhí)行w1函數(shù) ,并將 @w1 下面的函數(shù)作為w1函數(shù)的參數(shù),即:@w1 等價于 w1(f1) 所以,內(nèi)部就會去執(zhí)行:

def inner():

#驗證 1

#驗證 2

#驗證 3

f1() # func是參數(shù),此時 func 等于 f1

return inner# 返回的 inner,inner代表的是函數(shù),非執(zhí)行函數(shù) ,其實就是將原來的 f1 函數(shù)塞進另外一個函數(shù)中

w1的返回值將執(zhí)行完的w1函數(shù)返回值 賦值 給@w1下面的函數(shù)的函數(shù)名f1 即將w1的返回值再重新賦值給 f1,即:

新f1 = def inner():

#驗證 1

#驗證 2

#驗證 3

原來f1()

return inner所以,以后業(yè)務部門想要執(zhí)行 f1 函數(shù)時,就會執(zhí)行 新f1 函數(shù),在新f1 函數(shù)內(nèi)部先執(zhí)行驗證,再執(zhí)行原來的f1函數(shù),然后將原來f1 函數(shù)的返回值返回給了業(yè)務調(diào)用者。

如此一來, 即執(zhí)行了驗證的功能,又執(zhí)行了原來f1函數(shù)的內(nèi)容,并將原f1函數(shù)返回值 返回給業(yè)務調(diào)用者。Low BBB 你明白了嗎?要是沒明白的話,我晚上去你家?guī)湍憬鉀Q吧!!!

3. 再議裝飾器

# 定義函數(shù):完成包裹數(shù)據(jù)

def makeBold(fn):

def wrapped():

return "" + fn() + ""

return wrapped

# 定義函數(shù):完成包裹數(shù)據(jù)

def makeItalic(fn):

def wrapped():

return "" + fn() + ""

return wrapped

@makeBold

def test1():

return "hello world-1"

@makeItalic

def test2():

return "hello world-2"

@makeBold

@makeItalic

def test3():

return "hello world-3"

print(test1())

print(test2())

print(test3())

運行結(jié)果:

hello world-1

hello world-2

hello world-3

4. 裝飾器(decorator)功能引入日志

函數(shù)執(zhí)行時間統(tǒng)計

執(zhí)行函數(shù)前預備處理

執(zhí)行函數(shù)后清理功能

權(quán)限校驗等場景

緩存

5. 裝飾器示例

例1:無參數(shù)的函數(shù)

def check_time(action):

def do_action():

action()

return do_action

@check_time

def go_to_bed():

print('去睡覺')

go_to_bed()

上面代碼理解裝飾器執(zhí)行行為可理解成

result = check_time(go_to_bed) # 把go_to_bed 當做參數(shù)傳入給 check_time函數(shù),再定義一個變量用來保存check_time的運行結(jié)果

result() # check_time 函數(shù)的返回值result是一個函數(shù), result()再調(diào)用這個函數(shù),讓它再調(diào)用go_to_bed函數(shù)

例2:被裝飾的函數(shù)有參數(shù)

def check_time(action):

def do_action(a,b):

action(a,b)

return do_action

@check_time

def go_to_bed(a,b):

print('{}去{}睡覺'.format(a,b))

go_to_bed("zhangsan","床上")

例3:被裝飾的函數(shù)有不定長參數(shù)

def test(cal):

def do_cal(*args,**kwargs):

cal(*args,**kwargs)

return do_cal

@test

def demo(*args):

sum = 0

for x in args:

sum +=x

print(sum)

demo(1, 2, 3, 4)

例4:裝飾器中的return

def test(cal):

def do_cal(*args,**kwargs):

return cal(*args,**kwargs) # 需要再這里寫return語句,表示調(diào)用函數(shù),獲取函數(shù)的返回值并返回

return do_cal

@test

def demo(a,b):

return a + b

print(demo(1, 2)) #3

總結(jié):一般情況下為了讓裝飾器更通用,可以有return

例5:裝飾器帶參數(shù)

def outer_check(time):

def check_time(action):

def do_action():

if time < 22:

return action()

else:

return '對不起,您不具有該權(quán)限'

return do_action

return check_time

@outer_check(23)

def play_game():

return '玩兒游戲'

print(play_game())

提高:使用裝飾器實現(xiàn)權(quán)限驗證

以下代碼不要求掌握,如果能看懂最好,如果能自己手動寫出來,那就太棒了!

def outer_check(base_permission):

def check_permission(action):

def do_action(my_permission):

if my_permission & base_permission:

return action(my_permission)

else:

return '對不起,您不具有該權(quán)限'

return do_action

return check_permission

READ_PERMISSION = 1

WRITE_PERMISSION = 2

EXECUTE_PERMISSION = 4

@outer_check(base_permission=READ_PERMISSION)

def read(my_permission):

return '讀取數(shù)據(jù)'

@outer_check(base_permission=WRITE_PERMISSION)

def write(my_permission):

return '寫入數(shù)據(jù)'

@outer_check(base_permission=EXECUTE_PERMISSION)

def execute(my_permission):

return '執(zhí)行程序'

print(read(5))

函數(shù)應用:名片管理系統(tǒng)

# 定一個列表,用來存儲所有的名片信息(每個名片是一個字典)

info_list = []

def print_menu():

print("---------------------------")

print(" 名片管理系統(tǒng) V1.0")

print(" 1:添加名片")

print(" 2:刪除名片")

print(" 3:修改名片")

print(" 4:查詢名片")

print(" 5:顯示所有名片")

print(" 6:退出系統(tǒng)")

print("---------------------------")

def add_new_info():

"""添加名片信息"""

new_name = input("請輸入姓名:")

new_tel = input("請輸入手機號:")

new_qq = input("請輸入QQ:")

for temp_info in info_list:

if temp_info['name'] == new_name:

print("此用戶名已經(jīng)被占用,請重新輸入")

return # 如果一個函數(shù)只有return就相當于讓函數(shù)結(jié)束,沒有返回值

# 定義一個字典,用來存儲用戶的名片信息(這是一個字典)

info = {}

# 向字典中添加數(shù)據(jù)

info["name"] = new_name

info["tel"] = new_tel

info["qq"] = new_qq

# 向列表中添加這個字典

info_list.append(info)

def del_info():

"""刪除名片信息"""

del_num = int(input("請輸入要刪除的序號:"))

if 0 <= del_num < len(info_list):

del_flag = input("你確定要刪除么?yes or no")

if del_flag == "yes":

del info_list[del_num]

else:

print("輸入序號有誤,請重新輸入")

def modify_info():

"""修改名片信息"""

modify_num = int(input("請輸入要修改的序號:"))

if 0 <= modify_num < len(info_list):

print("你要修改的信息是:")

print("name:%s, tel:%s, QQ:%s" % (info_list[modify_num]['name'],

info_list[modify_num]['tel'],info_list[modify_num]['qq']))

info_list[modify_num]['name'] = input("請輸入新的姓名:")

info_list[modify_num]['tel'] = input("請輸入新的手機號:")

info_list[modify_num]['qq'] = input("請輸入新QQ:")

else:

print("輸入序號有誤,請重新輸入")

def search_info():

"""查詢名片信息"""

search_name = input("請輸入要查詢的名片姓名:")

for temp_info in info_list:

if temp_info['name'] == search_name:

print("查詢到的信息如下:")

print("name:%s, tel:%s, QQ:%s" % (temp_info['name'],

temp_info['tel'], temp_info['qq']))

break

else:

print("沒有您要找的信息....")

def print_all_info():

"""遍歷名片信息"""

print("序號\t姓名\t\t手機號\t\tQQ")

i = 0

for temp in info_list:

# temp是一個字典

print("%d\t%s\t\t%s\t\t%s" % (i, temp['name'], temp['tel'], temp['qq']))

i += 1

def main():

"""用來控制整個流程"""

while True:

# 1. 打印功能

print_menu()

# 2. 獲取用戶的選擇

num = input("請輸入要進行的操作(數(shù)字)")

# 3. 根據(jù)用戶選擇,做相應的事情

if num == "1":

# 添加名片

add_new_info()

elif num == "2":

# 刪除名片

del_info()

elif num == "3":

# 修改名片

modify_info()

elif num == "4":

# 查詢名片

search_info()

elif num == "5":

# 遍歷所有的信息

print_all_info()

elif num == "6":

# 退出系統(tǒng)

exit_flag = input("親,你確定要退出么?~~~~(>_<)~~~~(yes or no) ")

if exit_flag == "yes":

break

else:

print("輸入有誤,請重新輸入......")

# 程序的開始

main()

總結(jié)

以上是生活随笔為你收集整理的python高阶函数闭包装饰器_Python自学从入门到就业之高阶函数、嵌套函数、闭包、装饰器...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。