成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

修飾函數(shù)python的簡單介紹

Python嵌套函數(shù)和閉包

在Python語言中,可以在函數(shù)中定義函數(shù)。 這種在函數(shù)中嵌套定義的函數(shù)也叫內(nèi)部函數(shù)。我們來看下面的代碼:

成都創(chuàng)新互聯(lián)公司是專業(yè)的永新網(wǎng)站建設(shè)公司,永新接單;提供成都網(wǎng)站制作、成都網(wǎng)站建設(shè),網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行永新網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊,希望更多企業(yè)前來合作!

上述代碼中,定義了函數(shù)greet,在函數(shù)greet內(nèi)部又定義了一個函數(shù)inner_func, 并調(diào)用該函數(shù)打印了一串字符。

我們可以看到,內(nèi)部函數(shù)inner_func的定義和使用與普通函數(shù)基本相同。需要注意的是變量的作用域,在上述代碼中,函數(shù)參數(shù)name對于全局函數(shù)greet是局部變量,對內(nèi)部函數(shù)inner_func來說則是非局部變量。內(nèi)部函數(shù)對于非局部變量的訪問規(guī)則類似于標(biāo)準(zhǔn)的外部函數(shù)訪問全局變量。

從這個例子我們還可以看到內(nèi)部函數(shù)的一個作用,就是通過定義內(nèi)部函數(shù)的方式將一些功能隱藏起來,防止外部直接調(diào)用。常見的場景是,在一個復(fù)雜邏輯的函數(shù)中,將一些小的任務(wù)定義成內(nèi)部函數(shù),然后由這個外層函數(shù)使用,這樣可以使代碼更為清晰,易于維護(hù)。這些內(nèi)部函數(shù)只會在這個外層函數(shù)中使用,不能被其他函數(shù)或模塊使用。

在Python語言中, 函數(shù)也是對象,它可以被創(chuàng)建、賦值給變量,或者作為函數(shù)的返回值。我們來看下面這個例子。

在上述代碼中,在函數(shù)gen_greet內(nèi)部定義了inner_func函數(shù),并返回了一個inner_func函數(shù)對象。外部函數(shù)gen_greet返回了一個函數(shù)對象,所以像gen_greet這樣的函數(shù)也叫工廠函數(shù)。

在內(nèi)部函數(shù)inner_func中,使用了外部函數(shù)的傳參greet_words(非局部變量),以及函數(shù)的參數(shù)name(局部變量),來打印一個字符串。

接下來,調(diào)用gen_greet("Hello")創(chuàng)建一個函數(shù)對象say_hello,緊接著調(diào)用say_hello("Mr. Zhang"),輸出的結(jié)果為:Hello, Mr. Zhang!

同樣的,調(diào)用gen_greet("Hi")創(chuàng)建一個函數(shù)對象say_hi,調(diào)用say_hello("Mr. Zhang"),輸出的結(jié)果為:Hi,Tony!

我們可以發(fā)現(xiàn),gen_greet返回的函數(shù)對象具有記憶功能,它能夠把所需使用的非局部變量保存下來,用于后續(xù)被調(diào)用的時候使用。這種保存了非局部變量的函數(shù)對象被稱作閉包(closure)。

那么閉包是如何實現(xiàn)的呢?其實并不復(fù)雜,函數(shù)對象中有一個屬性__closure__,它就是在創(chuàng)建函數(shù)對象時用來保存這些非局部變量的。

__closure__屬性是一個元組或者None類型。在上述代碼中,我們可以通過下面方式查看:

函數(shù)的嵌套所實現(xiàn)的功能大都可以通過定義類的方式來實現(xiàn),而且類是更加面向?qū)ο蟮拇a編寫方式。

嵌套函數(shù)的一個主要用途是實現(xiàn)函數(shù)的裝飾器。我們看下面的代碼:

在上述代碼中,logger函數(shù)返回函數(shù)with_logging,with_logging則是打印了函數(shù)func的名稱及傳入的參數(shù),然后調(diào)用func, 并將參數(shù)傳遞給func。其中的@wraps(func)語句用于復(fù)制函數(shù)func的名稱、注釋文檔、參數(shù)列表等等,使得with_logging函數(shù)具有被裝飾的函數(shù)func相同的屬性。

代碼中接下來用@logger對函數(shù)power_func進(jìn)行修飾,它的作用等同于下面的代碼:

可見,裝飾器@符其實就是上述代碼的精簡寫法。

通過了解了嵌套函數(shù)和閉包的工作原理,我們在使用過程中就能夠更加得心應(yīng)手了。

python讓一個循環(huán)不影響其他代碼

循環(huán)是一種常用的程序控制結(jié)構(gòu)。我們常說,機(jī)器相比人類的最大優(yōu)點之一,就是機(jī)器可以不眠不休的重復(fù)做某件事情,但人卻不行。而“循環(huán)”,則是實現(xiàn)讓機(jī)器不斷重復(fù)工作的關(guān)鍵概念。

在循環(huán)語法方面,Python 表現(xiàn)的即傳統(tǒng)又不傳統(tǒng)。它雖然拋棄了常見的 for(init;condition;incrment) 三段式結(jié)構(gòu),但還是選擇了 for 和 while 這兩個經(jīng)典的關(guān)鍵字來表達(dá)循環(huán)。絕大多數(shù)情況下,我們的循環(huán)需求都可以用 forin來滿足, while相比之下用的則更少些。

雖然循環(huán)的語法很簡單,但是要寫好它確并不容易。在這篇文章里,我們將探討什么是“地道”的循環(huán)代碼,以及如何編寫它們。

什么是“地道”的循環(huán)?

“地道”這個詞,通常被用來形容某人做某件事情時,非常符合當(dāng)?shù)貍鹘y(tǒng),做的非常好。打個比方,你去參加一個朋友聚會,同桌的有一位廣東人,對方一開口,句句都是標(biāo)準(zhǔn)京腔、完美兒化音。那你可以對她說:“您的北京話說的真地道”。

既然“地道”這個詞形容的經(jīng)常是口音、做菜的口味這類實實在在的東西,那“地道”的循環(huán)代碼又是什么意思呢?讓我拿一個經(jīng)典的例子來解釋一下。

如果你去問一位剛學(xué)習(xí) Python 一個月的人:“如何在遍歷一個列表的同時獲取當(dāng)前下標(biāo)?”。他可能會交出這樣的代碼:

?

上面的循環(huán)雖然沒錯,但它確一點都不“地道”。一個擁有三年 Python 開發(fā)經(jīng)驗的人會說,代碼應(yīng)該這么寫:

enumerate() 是 Python 的一個內(nèi)置函數(shù),它接收一個“可迭代”對象作為參數(shù),然后返回一個不斷生成 (當(dāng)前下標(biāo),當(dāng)前元素) 的新可迭代對象。這個場景使用它最適合不過。

所以,在上面的例子里,我們會認(rèn)為第二段循環(huán)代碼比第一段更“地道”。因為它用更直觀的代碼,更聰明的完成了工作。

enumerate() 所代表的編程思路

不過,判斷某段循環(huán)代碼是否地道,并不僅僅是以知道或不知道某個內(nèi)置方法作為標(biāo)準(zhǔn)。我們可以從上面的例子挖掘出更深層的東西。

如你所見,Python 的 for 循環(huán)只有 forin這一種結(jié)構(gòu),而結(jié)構(gòu)里的前半部分 - 賦值給 item- 沒有太多花樣可玩。所以后半部分的 可迭代對象 是我們唯一能夠大做文章的東西。而以 enumerate() 函數(shù)為代表的“修飾函數(shù)”,剛好提供了一種思路:通過修飾可迭代對象來優(yōu)化循環(huán)本身。

這就引出了我的第一個建議。

建議1:使用函數(shù)修飾被迭代對象來優(yōu)化循環(huán)

使用修飾函數(shù)處理可迭代對象,可以在各種方面影響循環(huán)代碼。而要找到合適的例子來演示這個方法,并不用去太遠(yuǎn),內(nèi)置模塊 itertools 就是一個絕佳的例子。

簡單來說,itertools 是一個包含很多面向可迭代對象的工具函數(shù)集。我在之前的系列文章《容器的門道》里提到過它。

如果要學(xué)習(xí) itertools,那么 Python 官方文檔 是你的首選,里面有非常詳細(xì)的模塊相關(guān)資料。但在這篇文章里,側(cè)重點將和官方文檔稍有不同。我會通過一些常見的代碼場景,來詳細(xì)解釋它是如何改善循環(huán)代碼的。

1. 使用 product 扁平化多層嵌套循環(huán)

雖然我們都知道“扁平的代碼比嵌套的好”。但有時針對某類需求,似乎一定得寫多層嵌套循環(huán)才行。比如下面這段:

?

對于這種需要嵌套遍歷多個對象的多層循環(huán)代碼,我們可以使用 product() 函數(shù)來優(yōu)化它。product() 可以接收多個可迭代對象,然后根據(jù)它們的笛卡爾積不斷生成結(jié)果。

?

相比之前的代碼,使用 product() 的函數(shù)只用了一層 for 循環(huán)就完成了任務(wù),代碼變得更精煉了。

2. 使用 islice 實現(xiàn)循環(huán)內(nèi)隔行處理

有一份包含 Reddit 帖子標(biāo)題的外部數(shù)據(jù)文件,里面的內(nèi)容格式是這樣的:

?

可能是為了美觀,在這份文件里的每兩個標(biāo)題之間,都有一個 "---" 分隔符?,F(xiàn)在,我們需要獲取文件里所有的標(biāo)題列表,所以在遍歷文件內(nèi)容的過程中,必須跳過這些無意義的分隔符。

參考之前對 enumerate() 函數(shù)的了解,我們可以通過在循環(huán)內(nèi)加一段基于當(dāng)前循環(huán)序號的 if 判斷來做到這一點:

?

但對于這類在循環(huán)內(nèi)進(jìn)行隔行處理的需求來說,如果使用 itertools 里的 islice() 函數(shù)修飾被循環(huán)對象,可以讓循環(huán)體代碼變得更簡單直接。

islice(seq,start,end,step) 函數(shù)和數(shù)組切片操作( list[start:stop:step] )有著幾乎一模一樣的參數(shù)。如果需要在循環(huán)內(nèi)部進(jìn)行隔行處理的話,只要設(shè)置第三個遞進(jìn)步長參數(shù) step 值為 2 即可(默認(rèn)為 1)。

?

3. 使用 takewhile 替代 break 語句

有時,我們需要在每次循環(huán)開始時,判斷循環(huán)是否需要提前結(jié)束。比如下面這樣:

?

對于這類需要提前中斷的循環(huán),我們可以使用 takewhile() 函數(shù)來簡化它。takewhile(predicate,iterable)會在迭代 iterable 的過程中不斷使用當(dāng)前對象作為參數(shù)調(diào)用 predicate 函數(shù)并測試返回結(jié)果,如果函數(shù)返回值為真,則生成當(dāng)前對象,循環(huán)繼續(xù)。否則立即中斷當(dāng)前循環(huán)。

使用 takewhile 的代碼樣例:

?

itertools 里面還有一些其他有意思的工具函數(shù),他們都可以用來和循環(huán)搭配使用,比如使用 chain 函數(shù)扁平化雙層嵌套循環(huán)、使用 zip_longest 函數(shù)一次同時循環(huán)多個對象等等。

篇幅有限,我在這里不再一一介紹。如果有興趣,可以自行去官方文檔詳細(xì)了解。

4. 使用生成器編寫自己的修飾函數(shù)

除了 itertools 提供的那些函數(shù)外,我們還可以非常方便的使用生成器來定義自己的循環(huán)修飾函數(shù)。

讓我們拿一個簡單的函數(shù)舉例:

?

在上面的函數(shù)里,循環(huán)體內(nèi)為了過濾掉所有奇數(shù),引入了一條額外的 if 判斷語句。如果要簡化循環(huán)體內(nèi)容,我們可以定義一個生成器函數(shù)來專門進(jìn)行偶數(shù)過濾:

?

將 numbers 變量使用 even_only 函數(shù)裝飾后, sum_even_only_v2 函數(shù)內(nèi)部便不用繼續(xù)關(guān)注“偶數(shù)過濾”邏輯了,只需要簡單完成求和即可。

Hint:當(dāng)然,上面的這個函數(shù)其實并不實用。在現(xiàn)實世界里,這種簡單需求最適合直接用生成器/列表表達(dá)式搞定:sum(numfornuminnumbersifnum%2==0)

建議2:按職責(zé)拆解循環(huán)體內(nèi)復(fù)雜代碼塊

我一直覺得循環(huán)是一個比較神奇的東西,每當(dāng)你寫下一個新的循環(huán)代碼塊,就好像開辟了一片黑魔法陣,陣內(nèi)的所有內(nèi)容都會開始無休止的重復(fù)執(zhí)行。

但我同時發(fā)現(xiàn),這片黑魔法陣除了能帶來好處,它還會引誘你不斷往陣內(nèi)塞入越來越多的代碼,包括過濾掉無效元素、預(yù)處理數(shù)據(jù)、打印日志等等。甚至一些原本不屬于同一抽象的內(nèi)容,也會被塞入到同一片黑魔法陣內(nèi)。

python函數(shù)修飾符@的使用

python函數(shù)修飾符@ 修飾符 ‘@’符號用作函數(shù)修飾符是python2.4新增加的功能,修飾符必須出現(xiàn)在函數(shù)定義前一行,不允許和函數(shù)定義在同一行。也就是說@A def f(): 是非法的。 只可以在模塊或類定義層內(nèi)對函數(shù)進(jìn)行修飾,不允許修修飾一個類。一個修飾符就是一個函數(shù),它將被修飾的函數(shù)做為參數(shù),并返回修飾后的同名函數(shù)或其它可調(diào)用的東西。 本質(zhì)上講,裝飾符@類似于 回調(diào)函數(shù) ,把其它的函數(shù)(暫且稱為目的參數(shù),后面緊接著的函數(shù))作為自己的入?yún)?,在目的函?shù)執(zhí)行前,執(zhí)行一些自己的操作, 比如:計數(shù)、打印一些提示信息等,然后返回目的函數(shù)。下面列舉一個簡單的例子。

創(chuàng)建函數(shù)修飾符的規(guī)則:

(1)修飾符是一個函數(shù)

(2)修飾符取被修飾函數(shù)為參數(shù)

(3)修飾符返回一個新函數(shù)

(4)修飾符維護(hù)被維護(hù)函數(shù)的簽名

例子1: 被修飾函數(shù)不帶參數(shù)

運行結(jié)果:

例子2: 使用functools模塊提供的修改函數(shù)屬性的方法wraps

運行結(jié)果:

可見test1的函數(shù)名稱變了,如果某些代碼用到就會出問題,可以使用functools模塊提供的修改函數(shù)屬性的方法wraps

運行結(jié)果:

例子3: 被修飾函數(shù)帶參數(shù)

運行結(jié)果:

例子4: 修飾符帶參數(shù) ,需要比上面例子多一層包裝

運行結(jié)果:

python中怎么設(shè)定函數(shù)形參的類型

#Python

2.5

#這個可以用修飾器來完成

#但是一般不會限制參數(shù)類型

#給你個思路:

def

argfilter(*types):

def

deco(func):

#這是修飾器

def

newfunc(*args):

#新的函數(shù)

if

len(types)==len(args):

correct

=

True

for

i

in

range(len(args)):

if

not

isinstance(args[i],

types[i]):

#判斷類型

correct

=

False

if

correct:

return

func(*args)

#返回原函數(shù)值

else:

raise

TypeError

else:

raise

TypeError

return

newfunc

#由修飾器返回新的函數(shù)

return

deco

#返回作為修飾器的函數(shù)

@argfilter(int,

str)

#指定參數(shù)類型

def

func(i,

s):

#定義被修飾的函數(shù)

print

i,

s

#之后你想限制類型的話,

就這樣:

#@argfilter(第一個參數(shù)的類名,

第二個參數(shù)的類名,

...,

第N個參數(shù)的類名)

#def

yourfunc(第一個參數(shù),

第一個參數(shù),

...,

第N個參數(shù)):

#

...

#

#相當(dāng)于:

#def

yourfunc(第一個參數(shù),

第一個參數(shù),

...,

第N個參數(shù)):

#

...

#yourfunc

=

argfilter(第一個參數(shù)的類名,

第二個參數(shù)的類名,

...,

第N個參數(shù)的類名)(yourfunc)

網(wǎng)站名稱:修飾函數(shù)python的簡單介紹
文章來源:http://jinyejixie.com/article32/dodppsc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、品牌網(wǎng)站建設(shè)、全網(wǎng)營銷推廣、小程序開發(fā)、外貿(mào)建站ChatGPT

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)
合肥市| 丰原市| 宣汉县| 马尔康县| 苏州市| 阿克陶县| 视频| 合山市| 孟州市| 健康| 从江县| 铅山县| SHOW| 祁门县| 尼勒克县| 铜鼓县| 尼木县| 铁力市| 德兴市| 新乡县| 九寨沟县| 台东县| 晋城| 绥棱县| 南雄市| 丽江市| 松潘县| 定陶县| 宜春市| 苏州市| 长治市| 会理县| 胶州市| 平陆县| 宜君县| 雷州市| 科技| 康定县| 大冶市| 滨州市| 南和县|