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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python四大高阶函数_详谈Python高阶函数与函数装饰器(推荐)

發(fā)布時(shí)間:2025/3/15 python 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python四大高阶函数_详谈Python高阶函数与函数装饰器(推荐) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、上節(jié)回顧

Python2與Python3字符編碼問題,不管你是初學(xué)者還是已經(jīng)對(duì)Python的項(xiàng)目了如指掌了,都會(huì)犯一些編碼上面的錯(cuò)誤。我在這里簡(jiǎn)單歸納Python3和Python2各自的區(qū)別。

首先是Python3-->代碼文件都是用utf-8來解釋的。將代碼和文件讀到內(nèi)存中就變成了Unicode,這也就是為什么Python只有encode沒有decode了,因?yàn)閮?nèi)存中都將字符編碼變成了Unicode,而Unicode是萬(wàn)國(guó)碼,可以“翻譯”所以格式編碼的格式。Python3中str和bytes是兩種格式,bytes可以當(dāng)做二進(jìn)制的表現(xiàn)形式。

Python2使用系統(tǒng)默認(rèn)的字符編碼解釋代碼,所以要用utf-8解釋代碼,就必須在頭部申明;并且Python2中有解碼和編碼,但是解碼動(dòng)作是必須的而編碼動(dòng)作可以忽略,因?yàn)镻ython代碼加載到內(nèi)存中就是Unicode,這一點(diǎn)和python3一樣;Python2中還需要注意的就是str和bytes是一個(gè)意思。Python2 里面的str就是Python3中的bytes格式,而Python3中的str其實(shí)就是Unicode.

函數(shù)基礎(chǔ)(這里我就是用遞歸函數(shù)中的二分查找)

為什么使用函數(shù):將將程序進(jìn)行模塊設(shè)計(jì)

定義函數(shù)有三種形式:

- 無(wú)參函數(shù)

- 有參函數(shù)

- 空函數(shù)

PS:如果函數(shù)有多個(gè)返回值,那么返回的來的數(shù)據(jù)格式是元組

- 如何在函數(shù)傳入?yún)?shù)時(shí)限定參數(shù)數(shù)據(jù)格式。

def leon(x:int,y:int)->int:

pass

其中這里指定了x,y都必須是int類型 " -> "的意思是函數(shù)返回值也必須是int類型

print(yan.__annotations__):顯示形參的限定數(shù)據(jù)格式以及返回值的格式

a = [1,2,3,4,5,7,9,10,11,12,14,15,16,17,19,21] #形參中的num

def calc(num,find_num):

print(num)

mid = int(len(num) / 2) #中間數(shù)的下標(biāo)

if mid == 0: #遞歸函數(shù)非常重要的判斷條件

if num[mid] == find_num:

print("find it %s"%find_num)

else:

print("cannt find num")

if num[mid] == find_num: #直接找到不用遞歸,結(jié)束函數(shù)

print("find_num %s"%find_num)

elif num[mid] > find_num: #find_num應(yīng)該在左邊,向下遞歸

calc(num[0:mid],find_num)

elif num[mid] < find_num: #find_num應(yīng)該在右邊,向下遞歸

calc(num[mid+1:],find_num)

calc(a,12)

匿名函數(shù)

c = lambda x:x+1 #x就是形參,c就是這個(gè)匿名函數(shù)的對(duì)象

print(c(22))

高階函數(shù)-特性

1. 把一個(gè)函數(shù)的內(nèi)存地址傳給另外一個(gè)函數(shù),當(dāng)做參數(shù)

2.一個(gè)函數(shù)把另外一個(gè)函數(shù)的當(dāng)做返回值返回

def calc(a,b,c):

print(c(a) + c(b))

calc(-5,10,abs) #引用上一節(jié)的實(shí)例,將-5和10絕對(duì)值相加

二、高階函數(shù)(補(bǔ)充)

函數(shù)是第一類對(duì)象

函數(shù)可以被賦值

可以被當(dāng)做參數(shù)

可以當(dāng)做返回值

可以作為容器類型的元素

#函數(shù)可以被賦值

def leon():

print("in the leon")

l = leon

l()

#函數(shù)可以被當(dāng)做參數(shù)

def yan(x): #這里x形參,其實(shí)就是我們調(diào)用實(shí)參的函數(shù)名

x() #運(yùn)行函數(shù)

y = yan(leon)

#函數(shù)當(dāng)做返回值

def jian(x): 和上面一樣這這也必須傳入一個(gè)函數(shù)

return x

j = jian(leon) #這里需要注意一點(diǎn)就是這里的意思是運(yùn)行jian這個(gè)函數(shù)而這個(gè)函數(shù)返回的是x 也就是leon這個(gè)函數(shù)的內(nèi)存地址,也就是說這時(shí)候leon這個(gè)函數(shù)并沒有被執(zhí)行

j() #運(yùn)行 leon函數(shù)

#可以做為容器類型的元素

leon_dict = {"leon":leon}

leon_dict["leon"]() #這樣也可以運(yùn)行l(wèi)eon這個(gè)函數(shù)

三、閉包函數(shù)

1.什么是閉包?我來看一下,比較官網(wǎng)的概念(這不是我在官網(wǎng)上面找的,不過沒有關(guān)系,反正你們也看不懂):

閉包(Closure)是詞法閉包(Lexical Closure)的簡(jiǎn)稱,是引用了自由變量的函數(shù)。這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外。所以,閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。

懵逼了?不存在的。下面我用簡(jiǎn)潔的說一下,但是有一點(diǎn)很重要,閉包是裝飾器中的重點(diǎn),如果沒有把閉包正真理解,那么學(xué)完裝飾器之后會(huì)很快忘記。我們通過一個(gè)列子來說明下

import requests #首先導(dǎo)入一個(gè)模塊,這個(gè)可以不用記

def get(url): #定義一個(gè)get函數(shù)里面需要傳一個(gè)url的位置參數(shù)

def wapper(): #在定義一個(gè)wapper函數(shù)

res = requests.get(url) #這一步就是打開一個(gè)網(wǎng)頁(yè)

return res.text #將網(wǎng)頁(yè)以文字的形式返回

return wapper #返回最里層的wapper函數(shù)

g = get("http://www.baidu.com") #調(diào)用:首先因?yàn)樽饔糜虻脑?#xff0c;我們無(wú)法訪問到里層的wapper函數(shù),所以我們直接調(diào)用get函數(shù)這里返回了一個(gè)wapper函數(shù)

print(g()) # 然后我在調(diào)用g(get函數(shù))的對(duì)象,這樣是不是就訪問到里層的wapper函數(shù)呢

PS:這里我們可以把函數(shù)當(dāng)做一個(gè)特殊的變量,當(dāng)代碼從上向下執(zhí)行的時(shí)候,如果函數(shù)不被調(diào)用話,函數(shù)內(nèi)的代碼是不會(huì)被執(zhí)行的。就拿上面的上面的舉例,當(dāng)我們執(zhí)行g(shù)et函數(shù)的時(shí)候,這時(shí)候會(huì)返回一個(gè)wapper函數(shù)的內(nèi)存地址,但是這個(gè)時(shí)候wapper函數(shù)并沒有被執(zhí)行也就是說g()這時(shí)候返回的狀態(tài)其實(shí)就是wapper,這是我們只需要將g運(yùn)行,就等于運(yùn)行了wapper內(nèi)的代碼。

四、函數(shù)的嵌套調(diào)用

嵌套調(diào)用其實(shí)很好理解,就是在一個(gè)函數(shù)中調(diào)用另一個(gè)函數(shù)的結(jié)果,也就是return的東西,同樣的我們看一段非常簡(jiǎn)單的代碼來看一下。

#嵌套調(diào)用,在一個(gè)函數(shù)中調(diào)用另一個(gè)函數(shù)的功能

#calc這個(gè)函數(shù)就是在對(duì)比兩個(gè)數(shù)字的大小

def calc2(x,y):

if x >y :

return x

else:

return y

#我靠老板非常變態(tài),然你直接計(jì)算四個(gè)數(shù)字的大小,擦。

def calc4(a,b,c,d):

res1 = calc2(a,b) #res1的值,這里不就是calc2這個(gè)函數(shù)比較時(shí)最大的哪一個(gè)嗎。

res2 = calc2(res1,c)

res3 = calc2(res2,d)

return res3

通過上面的代碼我們做一記憶。什么時(shí)候會(huì)用到嵌套調(diào)用呢?很顯然,就是我們這個(gè)函數(shù)(calc4)需要另外一個(gè)函數(shù)的實(shí)行結(jié)果(return的y或者x)。

五、裝飾器(高級(jí)的閉包函數(shù))

就拿下面的這段代碼來說。如何在不改源代碼的情況下實(shí)現(xiàn)計(jì)算代碼的運(yùn)行時(shí)間

def geturl(url):

response = requests.get(url)

print(response.status_code)

geturl(http://www.baidu.com)

def timer(func):

def wapper(url):

start_time = time.time()

func(url)

stop_time = time.time()

so_time_is = stop_time - start_time

print("運(yùn)行時(shí)間%s"%so_time_is)

return wapper

@timer

def geturl(url):

response = requests.get(url)

print(response.status_code)

python = geturl(http://www.baidu.com)

圖解代碼

裝飾器必備:

@timer就是裝飾器,意思是裝飾它下面的函數(shù),而裝飾器和被裝飾的都是一個(gè)函數(shù)。

timer(裝飾器函數(shù)),首先它會(huì)有一個(gè)位置參數(shù)(func)名字隨意,但是必須并且只能是一個(gè)位置參數(shù)

func參數(shù)就是被裝飾的geturl這個(gè)函數(shù)

為什么func是geturl這個(gè)函數(shù)呢-->上面寫了一個(gè)裝飾器功能:geturl=timer(geturl),我們看到這里的timer中傳入的其實(shí)就是func函數(shù)所以func = geturl(被裝飾的函數(shù))

分析geturl=timer(geturl),首先我們可以得知timer這是一個(gè)閉包函數(shù),當(dāng)我們執(zhí)行這個(gè)閉包函數(shù),會(huì)把里層的函數(shù)(wapper)返回,也就是說timer(geturl)其實(shí)就是返回的wapper,所以就可以這樣理解了geturl==wapper,所以當(dāng)我們運(yùn)行g(shù)eturl的時(shí)候就相當(dāng)于在執(zhí)行wapper()這樣的一個(gè)操作;如果這里實(shí)在記不住,就這樣。咱上面不是有一個(gè)閉包函數(shù)嗎?你就把geturl=timer(geturl)中的geturl(執(zhí)行函數(shù)的返回結(jié)果)當(dāng)做上面g(函數(shù)調(diào)用的返回結(jié)果),然后在分別再執(zhí)行了下"g"或者"geturl”這個(gè)對(duì)象。

如果被裝飾者有位置參數(shù)的話,我們需要在wapper函數(shù)中加上對(duì)應(yīng)的位置參數(shù)用來接收,如果長(zhǎng)度是不固定的話還可以用*args和**kwargs

六、有參裝飾器

聽著名字顧名思義,就是在裝飾器中還有位置參數(shù)。

#一個(gè)low得不能再low得驗(yàn)證腳本,如果是顯示環(huán)境中所有數(shù)據(jù)必須是由數(shù)據(jù)庫(kù)或者一個(gè)靜態(tài)文件提供,并且登錄成功時(shí),需要保存用戶的一個(gè)狀態(tài)

def auth(auth_type): #有參裝飾器名稱

def auth_deco(func): #定義第二層函數(shù)名稱

def wrapper(*args,**kwargs): #最里層函數(shù),主要實(shí)現(xiàn)認(rèn)證功能

if auth_type == "file":

username = input("username>>:").strip()

password = input("username>>").strip()

if username == "leon" and password == "loveleon":

res = func(*args,**kwargs)

return res

elif auth_type == "mysql_auth":

print("mysql_auth...")

return func(*args,**kwargs)

return wrapper #第二層返回的是wrapper函數(shù),其實(shí)就是home

return auth_deco #第一層返回的結(jié)果等于第二層函數(shù)的名稱

@auth('file')

def home():

print("welcome")

home() #執(zhí)行home-->wrapper

有參函數(shù)必備知識(shí):

套路,通過上面無(wú)參裝飾器,我們得出了geturl=timer(geturl)這個(gè)等式。回到有參裝飾器,我們又會(huì)有什么樣子的等式呢?首先@auth("file")是一個(gè)裝飾器也就是一個(gè)函數(shù),所以我們定義了一個(gè)auth(auth_type)這個(gè)函數(shù),而這個(gè)函數(shù)返回的是什么呢?沒有錯(cuò)就是第二層函數(shù);到了這里我們就會(huì)發(fā)現(xiàn)@auth("file")其實(shí)就是@auth_deco,現(xiàn)在我們知道了現(xiàn)在裝飾器其實(shí)就是auth_deco,那剩下的還不知道怎么寫嗎?

整理公式,auth('file')-----------(return)> auth_deco----->@auth_deco ->home=auth_deco(home)

如果記不住?如果實(shí)在是記不住,其實(shí)就可以這樣理解,有參裝飾器無(wú)非就是在無(wú)參裝飾器上面加了一層(三層),然后在第一層返回了第二層的函數(shù),而到了第二層就和我們普通用的裝飾器是一毛一樣了

七、模塊導(dǎo)入

import ,創(chuàng)建一個(gè)leonyan.py的模塊文件,等待被導(dǎo)入

a = 10

b = 20

c = 30

def read1():

print("in the read1")

def read2():

print("in the read2")

導(dǎo)入leonyan.py文件(調(diào)用模塊文件和模塊文件在同一目錄下)

import leonyan #Python IDE這行會(huì)爆紅,但是不用管

leonyan.read1() #執(zhí)行l(wèi)eonyan這個(gè)包中的read1函數(shù)

leonyan.read2() #執(zhí)行l(wèi)eonyan這個(gè)包中read2函數(shù)

print(leonyan.a + leonyan.b + leonyan.c ) #輸出60

總結(jié):在Python中包的導(dǎo)入(import ***)會(huì)干三個(gè)事情:1:創(chuàng)建新的作用域;2:執(zhí)行該作用域的頂級(jí)代碼,比如你導(dǎo)入的那個(gè)包中有print執(zhí)行后就會(huì)直接在屏幕中輸出print的內(nèi)容;3:得到一個(gè)模塊名,綁定到該模塊內(nèi)的代碼

在模塊導(dǎo)入的時(shí)候給模塊起別名

import leonyan as ly

import pandas as pd #這是一個(gè)第三方模塊,以后的博客中會(huì)寫到,這是一個(gè)用于做統(tǒng)計(jì)的

給模塊起別名還是挺多的,在有些模塊的官方文檔中,還是比較推薦這種方法的,比如pandas的官方文檔中就是起了一個(gè)pd別名,總之a(chǎn)s就是一個(gè)模塊起別名

from *** import ***

from leonyan import read1 #引入直接調(diào)用

read1()

如果在調(diào)用模塊的函數(shù)作用域中有相同的同名的,會(huì)將調(diào)用過來的覆蓋。

在form ** import ** 中控制需要引用的變量(函數(shù)其實(shí)在未被執(zhí)行的時(shí)候也是一個(gè)存放在內(nèi)存中的變量)

from leonyan import read1,read2 在同一行中可以引用多個(gè),只需要用逗號(hào)隔開就行了

print(read1)

print(read2)

#這里打印的就是read1和read2的內(nèi)存地址

#需求我現(xiàn)在只需要導(dǎo)入read2

這時(shí)候我們就可以在leonyan這個(gè)函數(shù)中加上這么一行:

__all__ = ["read2"] #這里的意思就是別的文件調(diào)用為的時(shí)候用from ** import ** 只能拿到read2 這個(gè)函數(shù)的內(nèi)存地址,也就是只有read2可以被調(diào)用

把模塊當(dāng)做一個(gè)腳本執(zhí)行

我們可以通過模塊的全局變量__name__來查看模塊名:

當(dāng)做腳本運(yùn)行:

__name__ 等于'__main__'

作用:用來控制.py文件在不同的應(yīng)用場(chǎng)景下執(zhí)行不同的邏輯

if __name__ == '__main__':

#fib.py

def fib(n): # write Fibonacci series up to n

a, b = 0, 1

while b < n:

print(b, end=' ')

a, b = b, a+b

print()

def fib2(n): # return Fibonacci series up to n

result = []

a, b = 0, 1

while b < n:

result.append(b)

a, b = b, a+b

return result

if __name__ == "__main__":

import sys

fib(int(sys.argv[1]))

代碼執(zhí)行 Python flb.py 100

只需要簡(jiǎn)單了解的Python模塊導(dǎo)入搜索路徑

內(nèi)建(build-in) --> sys.path(sys.path是一個(gè)列表,而且第一個(gè)位置就是當(dāng)前文件夾)

模塊導(dǎo)入的重點(diǎn)-->包的導(dǎo)入

在實(shí)際的開發(fā)環(huán)境中,你不可能一個(gè)文件的代碼寫到底,當(dāng)然你也有可能會(huì)引用同文件夾中的其他模塊,但是你有沒有想過這一個(gè)項(xiàng)目不可能是你一個(gè)寫的,都是很多人協(xié)作開發(fā)。這樣就存在這樣的一個(gè)問題了;不同的人不可能用一臺(tái)電腦,也不可能在一個(gè)文件夾下面寫寫功能。他們也有自己的代碼文件夾,然后大家把功能通過接口的方式,提供調(diào)用。這時(shí)候就面臨這不同文件夾的調(diào)用問題。而這種問題也需要通過from ** import ** 調(diào)用。

上圖中我運(yùn)行“模塊導(dǎo)入.py”這個(gè)文件夾,首先我from Pythonscript.leonyan.command import config,因?yàn)槲覀兊眠\(yùn)行腳本和需要導(dǎo)入的包都在Pythonscript的目錄下面所以我直接通過絕對(duì)路徑導(dǎo)入,然后一層一層“.”下去,知道最后import了這個(gè)config文件,這里我們需要注意一點(diǎn):當(dāng)腳本在最外層運(yùn)行的時(shí)候sys.path 列表中的第一個(gè)參數(shù)就是運(yùn)行腳本的目錄,這是什么意思,這代表著你在別的包中有調(diào)用了其他的東西比如說我的config.py是調(diào)用了bing.py文件,這時(shí)候就必須寫絕對(duì)路徑,因?yàn)檫@在sys.path文件夾中已經(jīng)找不到了,也就是導(dǎo)入不進(jìn)來。

總結(jié):包的導(dǎo)入其實(shí)都是很簡(jiǎn)單的,你需要記住一點(diǎn):當(dāng)你導(dǎo)入Python內(nèi)建或者下載的第三方模塊直接用import 導(dǎo)入,如果是自己寫的就用from ** import ** 使用絕對(duì)目錄導(dǎo)入就行了,也就是從調(diào)用腳本的上級(jí)目錄開始導(dǎo)入。這樣可以保證不會(huì)報(bào)模塊導(dǎo)入的錯(cuò)誤了。

以上這篇詳談Python高階函數(shù)與函數(shù)裝飾器(推薦)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

總結(jié)

以上是生活随笔為你收集整理的python四大高阶函数_详谈Python高阶函数与函数装饰器(推荐)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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