PEP是Python Enhancement Proposal的縮寫,一般翻譯爲「Python加強提案」。每一個PEP都是一份爲Python社區提供的指導Python往更好的方向發展的技術文檔,其中的第8號加強提案(PEP 8)是針對Python語言編訂的代碼風格指南。儘管咱們能夠在保證語法沒有問題的前提下隨意書寫Python代碼,可是在實際開發中,採用一致的風格書寫出可讀性強的代碼是每一個專業的程序員應該作到的事情,也是每一個公司的編程規範中會提出的要求,這些在多人協做開發一個項目(團隊開發)的時候顯得尤其重要。咱們能夠從Python官方網站的PEP 8連接中找到該文檔,下面咱們對該文檔的關鍵部分作一個簡單的總結。html
不要在行尾加分號, 也不要用分號將兩條命令放在同一行。python
每行不超過80個字符。git
例外:程序員
Python會將圓括號,中括號和花括號中的行隱式的鏈接起來 , 你能夠利用這個特色. 若是須要, 你能夠在表達式外圍增長一對額外的圓括號。github
Yes: foo_bar(self, width, height, color='black', design=None, x='foo', emphasis=None, highlight=0) if (width == 0 and height == 0 and color == 'red' and emphasis == 'strong'):
若是一個文本字符串在一行放不下, 可使用圓括號來實現隱式行鏈接:算法
x = ('This will build a very long long ' 'long long long long long long string')
在註釋中,若是必要,將長的URL放在一行上。編程
Yes: # See details at # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html
No: # See details at # http://www.example.com/us/developer/documentation/api/content/\ # v2.0/csv_file_name_extension_full_specification.html
寧缺毋濫的使用括號。
除非是用於實現行鏈接, 不然不要在返回語句或條件語句中使用括號。 不過在元組兩邊使用括號是能夠的。api
Yes: if foo: bar() while x: x = bar() if x and y: bar() if not x: bar() return foo for (x, y) in dict.items(): ...
No: if (x): bar() if not(x): bar() return (foo)
PEP 8倡導用不一樣的命名風格來命名Python中不一樣的標識符,以便在閱讀代碼時可以經過標識符的名稱來肯定該標識符在Python中扮演了怎樣的角色(在這一點上,Python本身的內置模塊以及某些第三方模塊都作得並非很好)。app
在Python之禪(可使用import this查看)中有這麼一句名言:「There should be one-- and preferably only one --obvious way to do it.」,翻譯成中文是「作一件事應該有並且最好只有一種確切的作法」,這句話傳達的思想在PEP 8中也是無處不在的。編程語言
確保對模塊, 函數, 方法和行內註釋使用正確的風格。
最須要寫註釋的是代碼中那些技巧性的部分。若是你在下次代碼審查的時候必須解釋一下,那麼你應該如今就給它寫註釋。對於複雜的操做, 應該在其操做開始前寫上若干行註釋。對於不是一目瞭然的代碼, 應在其行尾添加註釋。
# We use a weighted dictionary search to find out where i is in # the array. We extrapolate position based on the largest num # in the array and the array size and then do binary search to # get the exact number. if i & (i-1) == 0: # True if i is 0 or a power of 2.
爲了提升可讀性,註釋應該至少離開代碼2個空格。
另外一方面, 毫不要描述代碼。 假設閱讀代碼的人比你更懂Python, 他只是不知道你的代碼要作什麼。
Python有一種獨一無二的的註釋方式: 使用文檔字符串。
文檔字符串是包, 模塊,類或函數裏的第一個語句。
這些字符串能夠經過對象的__doc__成員被自動提取, 而且被pydoc所用。(你能夠在你的模塊上運行pydoc試一把, 看看它長什麼樣)。
咱們對文檔字符串的慣例是使用三重雙引號"""( PEP-257 )。
一個文檔字符串應該這樣組織:
一個函數必需要有文檔字符串,除非它知足如下條件:
文檔字符串應該包含函數作什麼以及輸入和輸出的詳細描述。一般不該該描述「怎麼作」,除非是一些複雜的算法。
文檔字符串應該提供足夠的信息,當別人編寫代碼調用該函數的時候,它不須要看一行代碼,只要看文檔字符串就夠了。對於複雜的代碼,在代碼旁邊加註釋會比文檔字符串更有意義。
函數的文檔字符串格式,將函數按照參數、返回值、拋出異常等信息分小節進行描述,每小節應該以一個標題行開始,標題行以冒號結尾,除標題行外, 節的其餘內容應被縮進2個空格。
Args: 列出每一個參數的名字, 並在名字後使用一個冒號和一個空格, 分隔對該參數的描述.若是描述太長超過了單行80字符,使用2或者4個空格的懸掛縮進(與文件其餘部分保持一致). 描述應該包括所需的類型和含義. 若是一個函數接受*foo(可變長度參數列表)或者**bar (任意關鍵字參數), 應該詳細列出*foo和**bar. Returns: (或者 Yields: 用於生成器) 描述返回值的類型和語義. 若是函數返回None, 這一部分能夠省略. Raises: 列出與接口有關的全部異常.
def fetch_bigtable_rows(big_table, keys, other_silly_variable=None): """Fetches rows from a Bigtable. Retrieves rows pertaining to the given keys from the Table instance represented by big_table. Silly things may happen if other_silly_variable is not None. Args: big_table: An open Bigtable Table instance. keys: A sequence of strings representing the key of each table row to fetch. other_silly_variable: Another optional variable, that has a much longer name than the other args, and which does nothing. Returns: A dict mapping keys to the corresponding table row data fetched. Each row is represented as a tuple of strings. For example: {'Serak': ('Rigel VII', 'Preparer'), 'Zim': ('Irk', 'Invader'), 'Lrrr': ('Omicron Persei 8', 'Emperor')} If a key from the keys argument is missing from the dictionary, then that row was not found in the table. Raises: IOError: An error occurred accessing the bigtable.Table object. """ pass
類應該在其定義下有一個用於描述該類的文檔字符串。 若是你的類有公共屬性(Attributes), 那麼文檔中應該有一個屬性(Attributes)段。 而且應該遵照和函數參數相同的格式。
class SampleClass(object): """Summary of class here. Longer class information.... Longer class information.... Attributes: likes_spam: A boolean indicating if we like SPAM or not. eggs: An integer count of the eggs we have laid. """ def __init__(self, likes_spam=False): """Inits SampleClass with blah.""" self.likes_spam = likes_spam self.eggs = 0 def public_method(self): """Performs operation blah."""
「慣例」這個詞指的是「習慣的作法,常規的辦法,一向的作法」,與這個詞對應的英文單詞叫「idiom」。因爲Python跟其餘不少編程語言在語法和使用上仍是有比較顯著的差異,所以做爲一個Python開發者若是不能掌握這些慣例,就沒法寫出「Pythonic」的代碼。下面咱們總結了一些在Python開發中的慣用的代碼。
if __name__ == '__main__':
if x: if not x:
好的代碼:
name = 'Safe' pets = ['Dog', 'Cat', 'Hamster'] owners = {'Safe': 'Cat', 'George': 'Dog'} if name and pets and owners: print('We have pets!')
很差的代碼:
if name != '' and len(pets) > 0 and owners != {}: print('We have pets!')
if x in items: # 包含 for x in items: # 迭代
好的代碼:
name = 'Safe Hammad' if 'H' in name: print('This name has an H in it!')
很差的代碼:
name = 'Safe Hammad' if name.find('H') != -1: print('This name has an H in it!')
a, b = b, a
好的代碼
chars = ['S', 'a', 'f', 'e'] name = ''.join(chars) print(name) # Safe
很差的代碼
chars = ['S', 'a', 'f', 'e'] name = '' for char in chars: name += char print(name) # Safe
「It's Easier to Ask for Forgiveness than Permission.」
「Look Before You Leap」
好的代碼
d = {'x': '5'} try: value = int(d['x']) except (KeyError, TypeError, ValueError): value = None
很差的代碼
d = {'x': '5'} if 'x' in d and \ isinstance(d['x'], str) and \ d['x'].isdigit(): value = int(d['x']) else: value = None
好的代碼
fruits = ['orange', 'grape', 'pitaya', 'blueberry'] for index, fruit in enumerate(fruits): print(index, ':', fruit)
很差的代碼
fruits = ['orange', 'grape', 'pitaya', 'blueberry'] index = 0 for fruit in fruits: print(index, ':', fruit) index += 1
好的代碼
data = [7, 20, 3, 15, 11] result = [num * 3 for num in data if num > 10] print(result) # [60, 45, 33]
很差的代碼
data = [7, 20, 3, 15, 11] result = [] for i in data: if i > 10: result.append(i * 3) print(result) # [60, 45, 33]
好的代碼
keys = ['Safe', 'Bob', 'Thomas'] values = ['Hammad', 'Builder', 'Engine'] d = dict(zip(keys, values)) print(d) # {'Bob': 'Builder', # 'Safe': 'Hammad', # 'Thomas': 'Engine'}
很差的代碼
keys = ['Safe', 'Bob', 'Thomas'] values = ['Hammad', 'Builder', 'Engine'] d = {} for i, key in enumerate(keys): d[keys] = values[i] print(d) # {'Bob': 'Builder', # 'Safe': 'Hammad', # 'Thomas': 'Engine'}