免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
如何寫(xiě)一個(gè)更好的Python函數(shù)?

Happiness is a butterfly, which when pursued, is always just beyond your grasp, but which, if you will sit down quietly, may alight upon you.

幸福就是蝴蝶,追逐的時(shí)候,總抓不住,但當(dāng)你靜靜坐下,它就停歇在你身上。

每日掏心話

敏感的人易缺乏安全感和過(guò)分自卑。遇到點(diǎn)事常會(huì)設(shè)身處地的為他人著想,生怕自己言行舉止惹得他人不愉快,后來(lái)往往不愉快的人都是自己。


來(lái)自:量子位 報(bào)道 | 公眾號(hào) QbitAI | 責(zé)編:樂(lè)樂(lè)


程序員小樂(lè)(ID:study_tech)第 647 次推文   圖片來(lái)自網(wǎng)絡(luò)

往日回顧:10張令人噴飯的程序員漫畫(huà)

   正文   


Python雖然好用,但用好真的很難。

尤其是函數(shù)部分,只要寫(xiě)不好,后面的一連串人都會(huì)遭殃。

看又看不懂,測(cè)試起來(lái)也麻煩,維護(hù)又維護(hù)不動(dòng),真是讓人頭疼。

那怎么寫(xiě)好一個(gè)Python函數(shù)呢?

《Writing Idiomatic Python》一書(shū)的作者在Medium上發(fā)表了一篇文章,給出了6個(gè)建議。

希望能夠給你帶來(lái)幫助。

什么樣的函數(shù)是一個(gè)好函數(shù)?

“好”的Python函數(shù)和“差”的Python函數(shù)之間有什么差別呢?每個(gè)人都有自己的理解?;谖业睦斫?,如果一個(gè)Python函數(shù)能夠符合下面的大部分條件,我會(huì)認(rèn)為它是一個(gè)“好”函數(shù):

  • 命名合理

  • 單一功能

  • 包括文檔字符串

  • 返回一個(gè)值

  • 不超過(guò)50行

  • 是冪等函數(shù)或純函數(shù)

對(duì)許多人來(lái)說(shuō),這些要求可能顯得過(guò)于苛刻了。

不過(guò),我保證,如果你的函數(shù)遵循這些規(guī)則,你的代碼會(huì)非常漂亮,會(huì)讓其他的程序員都“饞哭”的。

下面,我將一一討論這些規(guī)則,然后總結(jié)它們是如何創(chuàng)造“好”函數(shù)的。

命名

在這個(gè)問(wèn)題上,我最喜歡的一句話是:

計(jì)算機(jī)科學(xué)中只有兩件事很讓人頭疼:緩存失效和命名。

盡管這聽(tīng)起來(lái)很莫名其妙,但給一個(gè)事情命名太難了。下面是一個(gè)反面案例:

def get knn(from_df):

原文中這個(gè)代碼沒(méi)有放上去,量子位根據(jù)上下文信息進(jìn)行了補(bǔ)充。

這個(gè)函數(shù)命名的第一個(gè)問(wèn)題是它使用了縮寫(xiě)。

對(duì)于那些并不出名的縮略詞來(lái)說(shuō),使用完整的英語(yǔ)單詞會(huì)更好??s寫(xiě)單詞的唯一原因是為了節(jié)省打字時(shí)間,但是每個(gè)現(xiàn)代編輯器都有自動(dòng)填充功能,所以你只需要鍵入一次全名就可以了。

縮寫(xiě)通常是特定領(lǐng)域的。在上面的代碼中,KNN指的是“K-Nearest Neighbors”,df指的是“DataFrame”,這是一個(gè)數(shù)據(jù)結(jié)構(gòu)。如果另一個(gè)不熟悉這些首字母縮寫(xiě)的程序員正在閱讀代碼,幾乎很難看懂。

關(guān)于這個(gè)函數(shù)的名字還有另外兩個(gè)小瑕疵:

  • “get”這個(gè)詞是無(wú)關(guān)緊要的。對(duì)于大多數(shù)命名比較好的函數(shù)來(lái)說(shuō),很明顯有一些東西會(huì)從函數(shù)中返回,它的名字將反映這一點(diǎn)。

  • from_df也不是必要的。如果沒(méi)有明確的參數(shù)名稱(chēng),函數(shù)的文檔字符串或類(lèi)型注釋會(huì)描述參數(shù)的類(lèi)型。

那么我們?nèi)绾沃孛@個(gè)函數(shù)呢?很簡(jiǎn)單:

def k_nearest_neighbors(dataframe):

即使是外行,這個(gè)函數(shù)要計(jì)算的內(nèi)容也很清楚,參數(shù)的名稱(chēng)(dataframe)也清楚地表明了參數(shù)類(lèi)型。

單一功能

單一功能原則不僅適用于類(lèi)和模塊,也同樣適用于函數(shù)。

一個(gè)函數(shù)應(yīng)該只有一個(gè)功能。也就是說(shuō),它應(yīng)該只做一件事。

一個(gè)重要的原因是,如果每個(gè)函數(shù)只做一件事,只有這件事發(fā)生了變化,才需要改變這個(gè)函數(shù)。

此外,如果這個(gè)函數(shù)的單個(gè)功能不再需要了,直接把它刪了就行了。

還是用例子來(lái)說(shuō)明吧。下面這個(gè)函數(shù),可以做不止一件“事情”:

def calculate_and print_stats(list_of_numbers):
    sum = sum(list_of_numbers) 
    mean = statistics.mean(list_of_numbers) 
    median = statistics.median(list_of_numbers) 
    mode = statistics.mode(list_of_numbers) 
    print('-----------------Stats-----------------') 
    print('SUM: {}'.format(sum) print('MEAN: {}'.format(mean)
    print('MEDIAN: {}'.format(median) 
    print('MODE: {}'.format(mode)

這個(gè)函數(shù)做了兩件事:一是計(jì)算一組關(guān)于數(shù)字列表的統(tǒng)計(jì)數(shù)據(jù),二是將它們打印到STDOUT。

如果需要計(jì)算新的或不同的統(tǒng)計(jì)數(shù)據(jù),或者需要改變輸出的格式,就需要對(duì)這個(gè)函數(shù)進(jìn)行調(diào)整。

所以,這個(gè)函數(shù)最好寫(xiě)成兩個(gè)獨(dú)立的函數(shù):一個(gè)用來(lái)執(zhí)行并返回計(jì)算結(jié)果,另一個(gè)用來(lái)獲取這些結(jié)果并打印出來(lái)。

這種處理方式,不僅能讓測(cè)試函數(shù)更容易,并且還允許這兩個(gè)部分有了遷移性,如果合適的話,還可能一起應(yīng)用到不同的模塊中。

在編程中,你會(huì)發(fā)現(xiàn)好多函數(shù)都可以做很多很多事情。同樣,為了可讀性和可測(cè)試性,這些函數(shù)應(yīng)該被分解成更小的函數(shù),每個(gè)函數(shù)只有一個(gè)功能。

文檔字符串(Docstrings)

雖然每個(gè)人似乎都知道PEP - 8,它定義了Python的樣式指南,但是很少有人知道PEP - 257,它是關(guān)于文檔字符串的。我再這里不簡(jiǎn)單地重復(fù)PEP - 257的內(nèi)容了,你可以在閑暇時(shí)讀一下。其中的關(guān)鍵內(nèi)容是:

  • 每個(gè)函數(shù)都需要有一個(gè)文檔字符串

  • 使用適當(dāng)?shù)恼Z(yǔ)法和標(biāo)點(diǎn)符號(hào);用完整的句子寫(xiě)

  • 首先對(duì)函數(shù)的作用進(jìn)行一句話的總結(jié)

  • 使用說(shuō)明性語(yǔ)言而不是描述性語(yǔ)言

在編寫(xiě)函數(shù)時(shí),要養(yǎng)成寫(xiě)文檔字符串的習(xí)慣,并在編寫(xiě)函數(shù)代碼之前嘗試寫(xiě)一下。

如果你不能寫(xiě)一個(gè)清晰的文檔字符串來(lái)描述函數(shù)做什么,就說(shuō)明你需要再考慮考慮為什么要寫(xiě)這個(gè)函數(shù)了。

返回值

函數(shù)可以被認(rèn)為是一些獨(dú)立的程序。它們以參數(shù)的形式接受一些輸入,并返回一些結(jié)果。

參數(shù)有沒(méi)有都可以,但從Python內(nèi)部的角度來(lái)看,返回值是必須要有的。你不可能創(chuàng)建一個(gè)沒(méi)有返回值的函數(shù)。如果函數(shù)沒(méi)有返回值,Python會(huì)“強(qiáng)制”返回None。你可以測(cè)試一下這段代碼:

? python3
Python 3.7.0 (default, Jul 23 2018, 20:22:55)
[Clang 9.1.0 (clang-902.0.39.2)] on darwin
Type 'help', 'copyright', 'credits' or 'license' for more information.
>>> def add(a, b):
...   print(a + b)
...
>>> b = add(1, 2)
3
>>> b
>>> b is None
True

你會(huì)發(fā)現(xiàn) b 的返回值實(shí)際上是 None。即使你寫(xiě)的函數(shù)沒(méi)有返回語(yǔ)句,它仍然會(huì)返回一些東西。而且,每個(gè)函數(shù)都應(yīng)該返回一個(gè)有用的值,測(cè)試起來(lái)也會(huì)更方便。畢竟,你寫(xiě)的代碼應(yīng)該能夠被測(cè)試。

試想一下,測(cè)試上面的add函會(huì)有多艱難。遵循這個(gè)概念,我們應(yīng)該這樣寫(xiě)代碼:

with open('foo.txt', 'r') as input_file:
    for line in input_file:
        if line.strip().lower().endswith('cat'):
            # ... do something useful with these lines

if line.strip().lower().endswith(‘cat’):這一行能夠工作,是因?yàn)槊總€(gè)字符串方法( strip ( )、lower ( )、end swith ( ) )都返回一個(gè)字符串作為調(diào)用函數(shù)的結(jié)果。

當(dāng)給定函數(shù)沒(méi)有返回值時(shí),有一些常見(jiàn)的原因:

“它所做的只是[一些與I / O相關(guān)的事情,比如將一個(gè)值保存到數(shù)據(jù)庫(kù)中]。我不能返回任何有用的東西?!?/h2>

我不同意。如果操作順利完成,函數(shù)可以返回True。

“我們修改了其中一個(gè)參數(shù),將其用作參考參數(shù)?!?/h2>

這里有兩點(diǎn)需要注意。首先,盡最大努力避免這種做法。用好了令人驚訝,用不好非常危險(xiǎn)。

其次,即使這樣做不可行,復(fù)制某個(gè)參數(shù)的成本太高,你也可以回到上一條建議。

“我需要返回多個(gè)值。單獨(dú)返回一個(gè)值是沒(méi)有意義的。”

可以使用元組返回多個(gè)值。

總是返回一個(gè)有用的值,調(diào)用者總是可以自由地忽略它們。

函數(shù)長(zhǎng)度

讓你讀一個(gè)200行的函數(shù),并說(shuō)出它是做什么的,你是什么感受?

函數(shù)的長(zhǎng)度直接影響可讀性,從而影響可維護(hù)性。所以要保持你的函數(shù)簡(jiǎn)短。50行是一個(gè)隨意的數(shù)字,在我看來(lái)是合理的。你編寫(xiě)的大多數(shù)函數(shù)應(yīng)該要短一些。

如果一個(gè)函數(shù)遵循單一功能原則,它很可能是相當(dāng)短的。如果它是純函數(shù)或是冪等的(下面討論) ,它也可能是短的。

那么,如果函數(shù)太長(zhǎng),應(yīng)該怎么做?重構(gòu)。這會(huì)改變程序的結(jié)構(gòu)而不改變其行為。

從一個(gè)長(zhǎng)函數(shù)中提取幾行代碼,并把它們變成自己的函數(shù)。這是縮短長(zhǎng)函數(shù)的最快、也是最常見(jiàn)的方式。

加上你給所有這些新函數(shù)取了合適的名稱(chēng),因此生成的代碼讀起來(lái)也會(huì)更容易。

冪等和函數(shù)純度

不管被調(diào)用了多少次,冪等函數(shù)總是在給定相同參數(shù)集的情況下返回相同的值。

結(jié)果不依賴(lài)于非局部變量、參數(shù)的可變性或來(lái)自任何I / O流的數(shù)據(jù)。下面的這個(gè)add_three(number)函數(shù)是冪等函數(shù):

def add_three(number):
    '''Return *number* + 3.'''
    return number + 3

不管一個(gè)人調(diào)用add_three(7)多少次,答案總是10。以下是一個(gè)非冪等函數(shù):

def add_three():
    '''Return 3 + the number entered by the user.'''
    number = int(input('Enter a number: '))
    return number + 3

這個(gè)函數(shù)的返回值取決于I / O,即用戶(hù)輸入的數(shù)字。對(duì)add_three()的每次調(diào)用都會(huì)返回不同的值。

如果它被調(diào)用兩次,用戶(hù)可以第一次輸入3,第二次輸入7,分別調(diào)用add_three()返回6和10。

冪等性的一個(gè)現(xiàn)實(shí)中例子是在電梯前點(diǎn)擊“向上”按鈕。第一次按時(shí),電梯會(huì)被“通知”你要上去。因?yàn)榘窗粹o是冪等的,所以反復(fù)按它都沒(méi)有什么影響。結(jié)果是一樣的。

為什么冪等很重要?

可維護(hù)性和可維護(hù)性。冪等函數(shù)很容易測(cè)試,因?yàn)樵谑褂孟嗤膮?shù)時(shí),它們總是返回相同的結(jié)果。

測(cè)試僅僅是檢查通過(guò)不同調(diào)用返回值的預(yù)期值。更重要的是,這些測(cè)試很快,這是單元測(cè)試中一個(gè)重要且經(jīng)常被忽視的問(wèn)題。

而在處理冪等函數(shù)時(shí),重構(gòu)是輕而易舉的事情。無(wú)論如何在函數(shù)之外更改代碼,使用相同的參數(shù)調(diào)用它的結(jié)果總是一樣的。

什么是純函數(shù)?

在函數(shù)編程中,如果一個(gè)函數(shù)既冪等又沒(méi)有可觀察到的副作用,它就被認(rèn)為是純函數(shù)。函數(shù)外部的任何東西都不會(huì)影響這個(gè)值。

然而,這并不意味著函數(shù)不能影響非局部變量或I / O流之類(lèi)的事情。例如,如果上面add_three(number)的冪等版本在返回結(jié)果之前打印了結(jié)果,那么它仍然被認(rèn)為是冪等的,因?yàn)楫?dāng)它訪問(wèn)I / O流時(shí),這個(gè)訪問(wèn)與從函數(shù)返回的值無(wú)關(guān)。

調(diào)用print ( )只是一個(gè)副作用:除了返回值之外,還與程序的其他部分或系統(tǒng)本身進(jìn)行了一些交互。

讓我們把我們的add_three(number)示例再向前推進(jìn)一步。我們可以編寫(xiě)下面的代碼片段來(lái)確定調(diào)用add_three(number)的次數(shù):

add_three_calls = 0
def add_three(number):
    '''Return *number* + 3.'''
    global add_three_calls
    print(f'Returning {number + 3}')
    add_three_calls += 1
    return number + 3
def num_calls():
    '''Return the number of times *add_three* was called.'''
    return add_three_calls

我們現(xiàn)在正在打印到控制臺(tái)(一個(gè)副作用)并修改一個(gè)非局部變量(另一個(gè)副作用),但是由于這兩者都不影響函數(shù)返回的值,它仍然是冪等的。

純函數(shù)沒(méi)有副作用。它不僅不使用任何“外部數(shù)據(jù)”來(lái)計(jì)算值,除了計(jì)算和返回所述值之外,它與系統(tǒng)/程序的其余部分都沒(méi)有交互。因此,雖然我們新的add_three(number)定義仍然是冪等的,但它不再是純的。

純函數(shù)沒(méi)有日志語(yǔ)句或print ( )調(diào)用。它們不使用數(shù)據(jù)庫(kù)或互聯(lián)網(wǎng)連接。它們不訪問(wèn)或修改非局部變量。它們不調(diào)用任何其他非純函數(shù)。

簡(jiǎn)而言之,它們無(wú)法做到愛(ài)因斯坦所說(shuō)的“遠(yuǎn)距離幽靈般的行動(dòng)”(在計(jì)算機(jī)科學(xué)環(huán)境中)。它們不會(huì)以任何方式修改程序或系統(tǒng)的其余部分。

在命令式編程(編寫(xiě)Python代碼時(shí)所做的那種)中,它們是所有函數(shù)中最安全的函數(shù)。

它們也很容易被測(cè)試和維護(hù),甚至比只是冪等函數(shù)更重要的是,測(cè)試它們基本上可以和執(zhí)行它們一樣快。

測(cè)試本身很簡(jiǎn)單:沒(méi)有數(shù)據(jù)庫(kù)連接或其他外部資源進(jìn)行模擬,也不需要安裝代碼,之后也沒(méi)有什么需要清理的。

明確地說(shuō),冪等性和純函數(shù)只是一種期望,不是必需的。也就是說(shuō),由于好處很多,我們可能會(huì)希望只編寫(xiě)純函數(shù)或冪等函數(shù),但這不現(xiàn)實(shí)。

重要的是,我們要有意識(shí)開(kāi)始寫(xiě)代碼來(lái)隔離副作用和外部依賴(lài)性。這會(huì)使得我們編寫(xiě)的每一行代碼都更容易被測(cè)試。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
excel公式應(yīng)用大全
python函數(shù)
Python知識(shí)點(diǎn)(史上最全)
Python系列(24)——不可不知“技能”之「函數(shù)」(三)
一、Python函數(shù)(函數(shù)定義、函數(shù)調(diào)用)用法詳解
一周快速?gòu)娜腴T(mén)到精通,60集Python視頻資料免費(fèi)分享
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服