介紹
你有沒有遇到過一段寫得很糟糕的Python代碼?我知道你們很多人都會點頭的。
編寫代碼是數據科學家或分析師角色的一部分。另一方面,編寫漂亮整潔的Python代碼完全是另一回事。作為一個精通分析或數據科學領域(甚至軟體開發)的程式設計師,這很可能會改變你的形象。
那麼,我們如何編寫這種所謂漂亮的Python代碼呢?
歡迎學習Python風格教程
數據科學和分析領域的許多人來自非編程背景。我們先從學習編程的基礎知識開始,接著理解機器學習背後的理論,然後開始徵服數據集。
在這個過程中,我們經常不練習核心編程,也不注意編程慣例。
這就是本Python風格教程將要解決的問題。我們將回顧PEP-8文檔中描述的Python編程約定,你將成為一個更好的程式設計師!
目錄
為什麼這個Python風格的教程對數據科學很重要?什麼是PEP8?了解Python命名約定Python風格教程的代碼布局熟悉正確的Python注釋Python代碼中的空格Python的一般編程建議自動格式化Python代碼為什麼這個Python風格的教程對數據科學很重要
有幾個原因使格式化成為編程的一個重要方面,尤其是對於數據科學項目:
可讀性好的代碼格式將不可避免地提高代碼的可讀性。這不僅會使你的代碼更有條理,而且會使讀者更容易理解程序中正在發生的事情。如果你的程序運行了數千行,這將特別有用。
你會有很多的數據幀、列表、函數、繪圖等,如果不遵循正確的格式準則,你甚至會很容易失去對自己代碼的跟蹤!
協作如果你在一個團隊項目上合作,大多數數據科學家都會這樣做,那麼好的格式化就成了一項必不可少的任務。
這樣可以確保代碼被正確理解而不產生任何麻煩。此外,遵循一個通用的格式模式可以在整個項目生命周期中保持程序的一致性。
Bug修復當你需要修復程序中的錯誤時,擁有一個格式良好的代碼也將有助於你。錯誤的縮進、不恰當的命名等都很容易使調試成為一場噩夢!
因此,最好是以正確的編寫風格來開始編寫你的程序!
考慮到這一點,讓我們快速概述一下本文將介紹的PEP-8樣式教程!
什麼是PEP-8
PEP-8或Python增強建議是Python編程的風格教程。它是由吉多·范羅森、巴裡·華沙和尼克·科格蘭寫的。它描述了編寫漂亮且可讀的Python代碼的規則。
遵循PEP-8的編碼風格將確保Python代碼的一致性,從而使其他讀者、貢獻者或你自己更容易理解代碼。
本文介紹了PEP-8指導原則中最重要的方面,如如何命名Python對象、如何構造代碼、何時包含注釋和空格,最後是一些很重要但很容易被大多數Python程式設計師忽略的一般編程建議。
讓我們學習編寫更好的代碼!
官方PEP-8文檔可以在這裡找到。
https://www.python.org/dev/peps/pep-0008/
了解Python命名約定
莎士比亞有句名言:「名字裡有什麼?」. 如果他當時遇到了一個程式設計師,他會很快得到一個答覆——「很多!」.
是的,當你編寫一段代碼時,你為變量、函數等選擇的名稱對代碼的可理解性有很大的影響。看看下面的代碼:
# 函數 1def func(x): a = x.split()[0] b = x.split()[1] return a, bprint(func('Analytics Vidhya'))# 函數 2def name_split(full_name): first_name = full_name.split()[0] last_name = full_name.split()[1] return first_name, last_nameprint(name_split('Analytics Vidhya'))# 輸出('Analytics', 'Vidhya')('Analytics', 'Vidhya')這兩個函數的作用是一樣的,但是後者提供了一個更好的直覺讓我們知道發生了什麼,即使沒有任何注釋!
這就是為什麼選擇正確的名稱和遵循正確的命名約定可以在編寫程序時可以產生巨大的不同。話雖如此,讓我們看看如何在Python中命名對象!
開頭命名
這些技巧可以應用於命名任何實體,並且應該嚴格遵守。
遵循相同的模式thisVariable, ThatVariable, some_other_variable, BIG_NO避免使用長名字,同時也不要太節儉的名字this_could_be_a_bad_name = 「Avoid this!」t = 「This isn\’t good either」使用合理和描述性的名稱。這將有助於以後你記住代碼的用途X = 「My Name」 # 防止這個full_name = 「My Name」 # 這個更好避免使用以數字開頭的名字1_name = 「This is bad!」避免使用特殊字符,如@、!、#、$等phone_ # 不好變量命名
變量名應始終為小寫blog = "Analytics Vidhya"對於較長的變量名,請使用下劃線分隔單詞。這提高了可讀性awesome_blog = "Analytics Vidhya"儘量不要使用單字符變量名,如「I」(大寫I字母)、「O」(大寫O字母)、「l」(小寫字母l)。它們與數字1和0無法區分。看看:O = 0 + l + I + 1全局變量的命名遵循相同的約定函數命名
遵循小寫和下劃線命名約定使用富有表現力的名字# 避免def con(): ...# 這個更好def connect(): ...如果函數參數名與關鍵字衝突,請使用尾隨下劃線而不是縮寫。例如,將break轉換為break_u而不是brk# 避免名稱衝突def break_time(break_): print(「Your break time is」, break_,」long」)類名命名
遵循CapWord(或camelCase或StudlyCaps)命名約定。每個單詞以大寫字母開頭,單詞之間不要加下劃線# 遵循CapWordclass MySampleClass: pass如果類包含具有相同屬性名的子類,請考慮向類屬性添加雙下劃線這將確保類Person中的屬性age被訪問為 _Person\age。這是Python的名稱混亂,它確保沒有名稱衝突
class Person: def __init__(self): self.__age = 18obj = Person() obj.__age # 錯誤obj._Person__age # 正確對異常類使用後綴「Error」class CustomError(Exception): 「」」自定義異常類「」」類方法命名
實例方法(不附加字符串的基本類方法)的第一個參數應始終為self。它指向調用對象類方法的第一個參數應始終為cls。這指向類,而不是對象實例class SampleClass: def instance_method(self, del_): print(「Instance method」) @classmethod def class_method(cls): print(「Class method」)包和模塊命名
儘量使名字簡短明了應遵循小寫命名約定對於長模塊名稱,首選下劃線避免包名稱使用下劃線testpackage # 包名稱sample_module.py # 模塊名稱常量命名
常量通常在模塊中聲明和賦值常量名稱應全部為大寫字母對較長的名稱使用下劃線# 下列常量變量在global.py模塊PI = 3.14GRAVITY = 9.8SPEED_OF_Light = 3*10**8Python風格教程的代碼布局
現在你已經知道了如何在Python中命名實體,下一個問題應該是如何用Python構造代碼!
老實說,這是非常重要的,因為如果沒有適當的結構,你的代碼可能會出問題,對任何評審人員來說都是最大的障礙。
所以,不用再多費吹灰之力,讓我們來了解一下Python中代碼布局的基礎知識吧!
縮進
它是代碼布局中最重要的一個方面,在Python中起著至關重要的作用。縮進告訴代碼塊中要包含哪些代碼行以供執行。缺少縮進可能是一個嚴重的錯誤。
縮進確定代碼語句屬於哪個代碼塊。想像一下,嘗試編寫一個嵌套的for循環代碼。在各自的循環之外編寫一行代碼可能不會給你帶來語法錯誤,但你最終肯定會遇到一個邏輯錯誤,這可能會在調試方面耗費時間。
遵循下面提到的縮進風格,以獲得一致的Python腳本風格。
始終遵循4空格縮進規則# 示例if value<0: print(「negative value」)# 另一個例子for i in range(5): print(「Follow this rule religiously!」)建議用空格代替制表符建議用空格代替制表符。但是當代碼已經用制表符縮進時,可以使用制表符。
if True: print('4 spaces of indentation used!')將大型表達式拆分成幾行處理這種情況有幾種方法。一種方法是將後續語句與起始分隔符對齊。
# 與起始分隔符對齊。def name_split(first_name, middle_name, last_name)# 另一個例子。ans = solution(value_one, value_two, value_three, value_four)第二種方法是使用4個空格的縮進規則。這將需要額外的縮進級別來區分參數和塊內其他代碼。
# 利用額外的縮進。def name_split( first_name, middle_name, last_name): print(first_name, middle_name, last_name)最後,你甚至可以使用「懸掛縮進」。懸掛縮進在Python上下文中是指包含圓括號的行以開括號結束的文本樣式,後面的行縮進,直到括號結束。
# 懸掛縮進ans = solution( value_one, value_two, value_three, value_four)縮進if語句可能是一個問題帶有多個條件的if語句自然包含4個空格。如你所見,這可能是個問題。隨後的行也將縮進,並且無法區分if語句和它執行的代碼塊。現在,我們該怎麼辦?
好吧,我們有幾種方法可以繞過它:
# 這是個問題。if (condition_one and condition_two): print(「Implement this」)一種方法是使用額外的縮進!
# 使用額外的縮進if (condition_one and condition_two): print(「Implement this」)另一種方法是在if語句條件和代碼塊之間添加注釋,以區分這兩者:
# 添加注釋。if (condition_one and condition_two): # 此條件有效 print(「Implement this」)括號的閉合假設你有一個很長的字典。你將所有的鍵值對放在單獨的行中,但是你將右括號放在哪裡?是在最後一行嗎?還是跟在最後一個鍵值對?如果放在最後一行,右括號位置的縮進是多少?
也有幾種方法可以解決這個問題。
一種方法是將右括號與前一行的第一個非空格字符對齊。
# learning_path = { 『Step 1』 : 』Learn programming』, 『Step 2』 : 『Learn machine learning』, 『Step 3』 : 『Crack on the hackathons』 }第二種方法是把它作為新行的第一個字符。
learning_path = { 『Step 1』 : 』Learn programming』, 『Step 2』 : 『Learn machine learning』, 『Step 3』 : 『Crack on the hackathons』}在二元運算符前換行如果你試圖在一行中放入太多的運算符和操作數,這肯定會很麻煩。相反,為了更好的可讀性,把它分成幾行。
現在很明顯的問題是——在操作符之前還是之後中斷?慣例是在操作符之前斷行。這有助於識別操作符和它所作用的操作數。
# 在操作符之前斷行gdp = (consumption + government_spending + investment + net_exports )使用空行
將代碼行聚在一起只會使讀者更難理解你的代碼。使代碼看起來更整潔、更美觀的一個好方法是在代碼中引入相應數量的空行。
頂層函數和類應該用兩個空行隔開#分離類和頂層函數class SampleClass(): passdef sample_function(): print("Top level function")類中的方法應該用一個空格行分隔# 在類中分離方法class MyClass(): def method_one(self): print("First method") def method_two(self): print("Second method")儘量不要在具有相關邏輯和函數的代碼段之間包含空行def remove_stopwords(text): stop_words = stopwords.words("english") tokens = word_tokenize(text) clean_text = [word for word in tokens if word not in stop_words] return clean_text可以在函數中少用空行來分隔邏輯部分。這使得代碼更容易理解def remove_stopwords(text): stop_words = stopwords.words("english") tokens = word_tokenize(text) clean_text = [word for word in tokens if word not in stop_words] clean_text = ' '.join(clean_text) clean_text = clean_text.lower() return clean_text行最大長度
一行不超過79個字符當你用Python編寫代碼時,不能在一行中壓縮超過79個字符。這是限制,應該是保持聲明簡短的指導原則。
你可以將語句拆分為多行,並將它們轉換為較短的代碼行# 分成多行num_list = [y for y in range(100) if y % 2 == 0 if y % 5 == 0]print(num_list)導入包
許多數據科學家之所以喜歡使用Python,部分原因是因為有太多的庫使得處理數據更加容易。因此,我們假設你最終將導入一堆庫和模塊來完成數據科學中的任何任務。
應該始終位於Python腳本的頂部應在單獨的行上導入單獨的庫import numpy as npimport pandas as pddf = pd.read_csv(r'/sample.csv')導入應按以下順序分組:標準庫導入相關第三方進口本地應用程式/庫特定導入在每組導入後包括一個空行import numpy as npimport pandas as pdimport matplotlibfrom glob import globimport spaCy import mypackage可以在一行中從同一模塊導入多個類from math import ceil, floor熟悉正確的Python注釋
理解一段未注釋的代碼可能是一項費力的工作。即使是代碼的原始編寫者,也很難記住一段時間後代碼行中到底發生了什麼。
因此,最好及時對代碼進行注釋,這樣讀者就可以正確地理解你試圖用這段代碼實現什麼。
一般提示
注釋總是以大寫字母開頭注釋應該是完整的句子更新代碼時更新注釋避免寫顯而易見之事的注釋注釋的風格
描述它們後面的代碼段與代碼段有相同的縮進從一個空格開始# 從用戶輸入字符串中刪除非字母數字字符。import reraw_text = input(『Enter string:『)text = re.sub(r'\W+', ' ', raw_text)內聯注釋
這些注釋與代碼語句位於同一行應與代碼語句至少分隔兩個空格以通常的#開頭,然後是空格不要用它們來陳述顯而易見的事情儘量少用它們,因為它們會分散注意力info_dict = {} # 字典,用於存儲提取的信息文檔字符串
用於描述公共模塊、類、函數和方法也稱為「docstrings」它們之所以能在其他注釋中脫穎而出,是因為它們是用三重引號括起來的如果docstring以單行結尾,則在同一行中包含結束符「」」如果docstring分為多行,請在新行中加上結束符「」」def square_num(x): """返回一個數的平方.""" return x**2def power(x, y): """多行注釋。 返回x**y. """ return x**yPython代碼中的空格
在編寫漂亮的代碼時,空格常常被忽略為一個微不足道的方面。但是正確使用空格可以大大提高代碼的可讀性。它們有助於防止代碼語句和表達式過於擁擠。這不可避免地幫助讀者輕鬆地瀏覽代碼。
關鍵
避免將空格立即放在括號內# 正確的方法df[『clean_text』] = df[『text』].apply(preprocess)不要在逗號、分號或冒號前加空格# 正確name_split = lambda x: x.split()字符和左括號之間不要包含空格# 正確print(『This is the right way』)# 正確for i in range(5): name_dict[i] = input_list[i]使用多個運算符時,只在優先級最低的運算符周圍包含空格# 正確ans = x**2 + b*x + c在分片中,冒號充當二進位運算符它們應該被視為優先級最低的運算符。每個冒號周圍必須包含相等的空格
# 正確df_valid = df_train[lower_bound+5 : upper_bound-5]應避免尾隨空格函數參數默認值不要在=號周圍有空格def exp(base, power=2): return base**power請始終在以下二進位運算符的兩邊用單個空格括起來:賦值運算符(=,+=,-=,等)比較(=,<,>!=,<>,<=,>=,輸入,不在,是,不是)布爾值(and,or,not)# 正確brooklyn = [『Amy』, 『Terry』, 『Gina』, 'Jake']count = 0for name in brooklyn: if name == 『Jake』: print(『Cool』) count += 1Python的一般編程建議
通常,有很多方法來編寫一段代碼。當它們完成相同的任務時,最好使用推薦的編寫方法並保持一致性。我在這一節已經介紹了其中的一些。
與「None」之類的進行比較時,請始終使用「is」或「is not」。不要使用相等運算符# 錯誤if name != None: print("Not null")# 正確if name is not None: print("Not null")不要使用比較運算符將布爾值與TRUE或FALSE進行比較。雖然使用比較運算符可能很直觀,但沒有必要使用它。只需編寫布爾表達式# 正確if valid: print("Correct")# 錯誤if valid == True: print("Wrong")與其將lambda函數綁定到標識符,不如使用泛型函數。因為將lambda函數分配給標識符違背了它的目的。回溯也會更容易# 選擇這個def func(x): return None# 而不是這個func = lambda x: x**2捕獲異常時,請命名要捕獲的異常。不要只使用一個光禿禿的例外。這將確保當你試圖中斷執行時,異常塊不會通過鍵盤中斷異常來掩蓋其他異常try: x = 1/0except ZeroDivisionError: print('Cannot divide by zero')與你的返回語句保持一致。也就是說,一個函數中的所有返回語句都應該返回一個表達式,或者它們都不應該返回表達式。另外,如果return語句不返回任何值,則返回None而不是什麼都不返回# 錯誤def sample(x): if x > 0: return x+1 elif x == 0: return else: return x-1# 正確def sample(x): if x > 0: return x+1 elif x == 0: return None else: return x-1如果要檢查字符串中的前綴或後綴,請使用「.startswith()」和「.endswith()",而不是字符串切片。它們更乾淨,更不容易出錯
# 正確if name.endswith('and'): print('Great!')自動格式化Python代碼
當你編寫小的程序時,格式化不會成為一個問題。但是想像一下,對於一個運行成千行的複雜程序,必須遵循正確的格式規則!這絕對是一項艱巨的任務。而且,大多數時候,你甚至不記得所有的格式規則。
我們如何解決這個問題呢?好吧,我們可以用一些自動格式化程序來完成這項工作!
自動格式化程序是一個程序,它可以識別格式錯誤並將其修復到位。Black就是這樣一種自動格式化程序,它可以自動將Python代碼格式化為符合PEP8編碼風格的代碼,從而減輕你的負擔。
BLACK:https://pypi.org/project/black/
通過在終端中鍵入以下命令,可以使用pip輕鬆安裝它:
pip install black但是讓我們看看black在現實世界中有多大的幫助。讓我們用它來格式化以下類型錯誤的程序:
現在,我們要做的就是,前往終端並鍵入以下命令:
black style_script.py完成後,black可能已經完成了更改,你將收到以下消息:
一旦再次嘗試打開程序,這些更改將反映在程序中:
正如你所看到的,它已經正確地格式化了代碼,在你不小心違反格式化規則的情況下它會有幫助。
Black還可以與Atom、Sublime Text、visualstudio代碼,甚至Jupyter Notebook集成在一起!這無疑是一個你永遠不會錯過的插件。
除了black,還有其他的自動格式化程序,如autoep8和yapf,你也可以嘗試一下!
結尾
我們已經在Python風格教程中討論了很多關鍵點。如果你在代碼中始終遵循這些原則,那麼你將最終得到一個更乾淨和可讀的代碼。
另外,當你作為一個團隊在一個項目中工作時,遵循一個共同的標準是有益的。它使其他合作者更容易理解。開始在Python代碼中加入這些風格技巧吧!