日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

說說Python編碼規(guī)范

 測(cè)試開發(fā)技術(shù) 2022-06-18 發(fā)布于廣東


前言

        已有近兩個(gè)月沒有發(fā)表過文章了,前段時(shí)間外甥和女兒過來這邊渡暑假,平常晚上和周末時(shí)間都陪著她們了,趁這個(gè)周末有空,再抽空再把這塊拾起來。
         這么久沒寫了,再次拿起鍵盤,想想,發(fā)表些什么呢,想起上次公司的代碼評(píng)審委員會(huì)下周其中一個(gè)議題是關(guān)于Python編碼規(guī)范的整理,那就趁熱打鐵,整理一份關(guān)于Python編碼規(guī)范的文章,也為那些寫Python的人,提供一些編碼注意的一些事項(xiàng)或者說是參考吧。

編碼規(guī)范的作用

        規(guī)范故明思義,就是通過不斷的總結(jié),吸取好的點(diǎn),從而形成的一份大家共同需要遵守的行為契約,
網(wǎng)上有很多版本的編碼規(guī)范,基本上都是遵循 PEP8 的規(guī)范。那么什么是PEP8呢?
        PEP是 Python Enhancement Proposal 的縮寫,簡單來說,是python增強(qiáng)建議書的意思。它描述了Python編程風(fēng)格的方方面面。在遵守這個(gè)文檔的條件下,不同程序員編寫的Python代碼可以保持最大程度的相似風(fēng)格。
這樣就易于閱讀,易于在程序員之間交流。


下面就說說Python編碼時(shí),應(yīng)該遵守的編碼規(guī)范有哪些。

編碼需遵守的規(guī)范

編碼

  • 所有的 Python 腳本文件都應(yīng)在文件頭標(biāo)上如下標(biāo)識(shí)或其兼容格式的標(biāo)識(shí): # -- coding:utf-8 --

分號(hào)

  • 不要在行尾加分號(hào), 也不要用分號(hào)將兩條命令放在同一行。

換行

  • 常規(guī)下,每一行代碼控制在 80 字符以內(nèi)

  • 以下情況除外:

    • 長的導(dǎo)入模塊語句

    • 注釋里的URL

  • 使用 \ 或 () 控制換行,舉例:

      def foo(first, second, third, fourth, fifth,
              sixth, and_some_other_very_long_param):
          user = User.objects.filter_by(first=first, second=second, third=third)           .skip(100).limit(100)           .all()
    
      text = ('Long strings can be made up ''of several shorter strings.')
  • 如果行長到連第一個(gè)括號(hào)內(nèi)的參數(shù)都放不下,則每個(gè)元素都單獨(dú)占一行:

  • 折疊長行的首選方法是使用Python支持的圓括號(hào)、方括號(hào)(brackets)和花括號(hào)(braces)內(nèi)的行延續(xù)。但是有時(shí)也可以適當(dāng)使用反斜杠 \ 。

括號(hào)

  • 寧缺毋濫的使用括號(hào)

  • 除非是用于實(shí)現(xiàn)行連接, 否則不要在返回語句或條件語句中使用括號(hào). 不過在元組兩邊使用括號(hào)是可以的.


    推薦: if foo:
             bar()while x:
             x = bar()if x and y:
             bar()if not x:
             bar()return foo         for (x, y) in dict.items(): ..
    不推薦:  if (x):
             bar()if not(x):
             bar()return (foo)

縮進(jìn)

  • 用4個(gè)空格來縮進(jìn)代碼

  • 絕對(duì)不要用tab, 也不要tab和空格混用,否則容易出現(xiàn) IndentationError

  • 使用任何編輯器寫 Python,請(qǐng)把一個(gè) tab 展開為 4 個(gè)空格

空行

  • 頂級(jí)定義之間空兩行, 比如函數(shù)或者類定義. 方法定義, 類定義與第一個(gè)方法之間, 都應(yīng)該空一行. 函數(shù)或方法中, 某些地方要是你覺得合適, 就空一行.

  • function 和 class 頂上兩個(gè)空行

  • class 的 method 之間一個(gè)空行

  • 函數(shù)內(nèi)邏輯無關(guān)的段落之間空一行,不要過度使用空行

  • 不要把多個(gè)語句寫在一行,然后用 ; 隔開

  • if/for/while 語句中,即使執(zhí)行語句只有一句,也要另起一行

  • 在類、函數(shù)的定義間加空行;

  • 在import不同種類的模塊間加空行;

  • 在函數(shù)中的邏輯段落間加空行,即把相關(guān)的代碼緊湊寫在一起,作為一個(gè)邏輯段落,段落間以空行分隔;

空格

  • 總體原則,避免不必要的空格。

  • 各種右括號(hào)前不要加空格。

  • 函數(shù)的左括號(hào)前不要加空格。如Func(1)。

  • 序列的左括號(hào)前不要加空格。如list[2]。

  • 操作符左右各加一個(gè)空格,不要為了對(duì)齊增加空格。

  • 函數(shù)默認(rèn)參數(shù)使用的賦值符左右省略空格。

  • 不要將多句語句寫在同一行,盡管使用';’允許。

  • if/for/while語句中,即使執(zhí)行語句只有一句,也必須另起一行。

  • 在二元算術(shù)、邏輯運(yùn)算符前后加空格如:a = b + c

  • 在 list, dict, tuple, set, 參數(shù)列表的 , 后面加一個(gè)空格

  • 在 dict 的 : 后面加一個(gè)空格

  • 在注釋符號(hào) # 后面加一個(gè)空格,但是 #!/usr/bin/python 的 # 后不能有空格

  • 操作符兩端加一個(gè)空格,如 +, -, *, /, |, &, =

  • 接上一條,在參數(shù)列表里的 = 兩端不需要空格

  • 括號(hào)((), {}, [])內(nèi)的兩端不需要空格

  • 括號(hào)內(nèi)不要有空格.

  • 不要在逗號(hào), 分號(hào), 冒號(hào)前面加空格, 但應(yīng)該在它們后面加(除了在行尾).

    推薦: if x == 4:print x, y
         x, y = y, x
    不推薦:  if x == 4 :print x , y
     x , y = y , x
  • 在二元操作符兩邊都加上一個(gè)空格, 比如賦值(=), 比較(==, <, >, !=, <>, <=, >=, in, not in, is, is not), 布爾(and, or, not). 至于算術(shù)操作符兩邊的空格該如何使用, 需要你自己好好判斷. 不過兩側(cè)務(wù)必要保持一致.

    推薦: x == 1
    不推薦:  x<1
  • 當(dāng)’=’用于指示關(guān)鍵字參數(shù)或默認(rèn)參數(shù)值時(shí), 不要在其兩側(cè)使用空格.

      推薦: def complex(real, imag=0.0): return magic(r=real, i=imag)
      不推薦:  def complex(real, imag = 0.0): return magic(r = real, i = imag)
  • 不要用空格來垂直對(duì)齊多行間的標(biāo)記, 因?yàn)檫@會(huì)成為維護(hù)的負(fù)擔(dān)(適用于:, #, =等):

    推薦:
         foo = 1000  # 注釋
         long_name = 2  # 注釋不需要對(duì)齊

         dictionary = {"foo": 1,"long_name": 2,}
    不推薦:
         foo       = 1000  # 注釋
         long_name = 2     # 注釋不需要對(duì)齊

         dictionary = {"foo"      : 1,"long_name": 2,}

Shebang

  • 大部分.py文件不必以#!作為文件的開始

  • 程序的main文件應(yīng)該以 #!/usr/bin/python2或者 #!/usr/bin/python3開始.

補(bǔ)充知識(shí): 此處解釋一下何為Shebang,Shebang就是
是一個(gè)由井號(hào)和嘆號(hào)構(gòu)成的字符串行(#!), 其出現(xiàn)在文本文件的第一行的前兩個(gè)字符. 在文件中存在Shebang的情況下,
類Unix操作系統(tǒng)的程序載入器會(huì)分析Shebang后的內(nèi)容, 將這些內(nèi)容作為解釋器指令, 并調(diào)用該指令,
并將載有Shebang的文件路徑作為該解釋器的參數(shù). 例如, 以指令#!/bin/sh開頭的文件在執(zhí)行時(shí)會(huì)實(shí)際調(diào)用/bin/sh程序.)#!先用于幫助內(nèi)核找到Python解釋器, 但是在導(dǎo)入模塊時(shí), 將會(huì)被忽略. 因此只有被直接執(zhí)行的文件中才有必要加入#!

注釋

  • 為了提高可讀性, 塊注釋和行注釋注釋應(yīng)該至少離開代碼2個(gè)空格.

  • 塊注釋,在一段代碼前增加的注釋。在'#’后加一空格。段落之間以只有'#’的行間隔。比如:

      # Description : Module config.
      # 
      # Input : None
      #
      # Output : None
  • 行注釋,在一句代碼后加注釋。比如:x = x + 1            # Increment x

  • 為所有的共有模塊、函數(shù)、類、方法寫docstrings;非共有的沒有必要,但是可以寫注釋(在def的下一行)。

  • 如果docstring要換行

      """Return a foobang
    
      Optional plotz says to frobnicate the bizbaz first.
    
      """
  • 文檔字符串 docstring, 是 package, module, class, method, function 級(jí)別的注釋,可以通過 doc 成員訪問到,注釋內(nèi)容在一對(duì) “”” 符號(hào)之間

  • function, method 的文檔字符串應(yīng)當(dāng)描述其功能、輸入?yún)?shù)、返回值,如果有復(fù)雜的算法和實(shí)現(xiàn),也需要寫清楚

  • 優(yōu)先使用英文寫注釋,英文不好全部寫中文,否則更加看不懂

  • 注釋塊:注釋塊通常應(yīng)用于跟隨其后的一些 (或者全部) 代碼,并和這些代碼有著相同的縮進(jìn) 層次。注釋塊中每行以 '#’ 和一個(gè)空格開始 (除非它是注釋內(nèi)的縮進(jìn)文本)。
    注釋塊內(nèi)的段落以僅含單個(gè) '#’ 的行分割

  • 行內(nèi)注釋:一個(gè)行內(nèi)注釋是和語句在同一行的注釋。行內(nèi)注釋應(yīng)該至少用兩個(gè)空格和語句分開。 它們應(yīng)該以一個(gè) '#’ 和單個(gè)空格開始。

異常

  • 不要輕易使用 try/except

  • except 后面需要指定捕捉的異常,裸露的 except 會(huì)捕捉所有異常,意味著會(huì)隱藏潛在的問題

  • 可以有多個(gè) except 語句,捕捉多種異常,分別做異常處理

  • 使用 finally 子句來處理一些收尾操作

  • try/except 里的內(nèi)容不要太多,只在可能拋出異常的地方使用

  • 從 Exception 而不是 BaseException 繼承自定義的異常類

Class(類)

  • 使用 super 調(diào)用父類的方法

  • 支持多繼承,即同時(shí)有多個(gè)父類,建議使用 Mixin

  • 如果一個(gè)類不繼承自其它類, 就顯式的從object繼承. 嵌套類也一樣.

    推薦: 
    class SampleClass(object):
        pass
    class OuterClass(object):
        pass
    class InnerClass(object):
        pass

    class ChildClass(ParentClass):
    """Explicitly inherits from another class already."""
        pass
    不推薦: 
    class SampleClass:
        pass
    class OuterClass:
        pass   
    class InnerClass:
        pass

這是繼承自 object 是為了使屬性(properties)正常工作, 并且這樣可以保護(hù)你的代碼, 使其不受Python 3000的一個(gè)特殊的潛在不兼容性影響. 這樣做也定義了一些特殊的方法, 這些方法實(shí)現(xiàn)了對(duì)象的默認(rèn)語義, 包括 new, init, delattr, getattribute, setattr, hash, repr, and str .

引號(hào)

  • 在同一個(gè)文件中, 保持使用字符串引號(hào)的一致性. 使用單引號(hào)’或者雙引號(hào)”之一用以引用字符串, 并在同一文件中沿用. 在字符串內(nèi)可以使用另外一種引號(hào),

  • 為多行字符串使用三重雙引號(hào)”””而非三重單引號(hào)’’’. 當(dāng)且僅當(dāng)項(xiàng)目中使用單引號(hào)’來引用字符串時(shí), 才可能會(huì)使用三重’’’為非文檔字符串的多行字符串來標(biāo)識(shí)引用. 文檔字符串必須使用三重雙引號(hào)”””. 不過要注意, 通常用隱式行連接更清晰, 因?yàn)槎嘈凶址c程序其他部分的縮進(jìn)方式不一致.

文件和sockets

  • 在文件和sockets結(jié)束時(shí), 顯式的關(guān)閉它.

  • 推薦使用 “with”語句 以管理文件:

      with open("hello.txt") as hello_file:      for line in hello_file:          print line
  • 對(duì)于不支持使用”with”語句的類似文件的對(duì)象,使用 contextlib.closing():

      import contextlib  with contextlib.closing(urllib.urlopen("http://www./")) as front_page:      for line in front_page:          print line

TODO注釋

  • TODO注釋應(yīng)該在所有開頭處包含”TODO”字符串, 緊跟著是用括號(hào)括起來的你的名字, email地址或其它標(biāo)識(shí)符. 然后是一個(gè)可選的冒號(hào). 接著必須有一行注釋, 解釋要做什么

  • 如果你的TODO是”將來做某事”的形式, 那么請(qǐng)確保你包含了一個(gè)指定的日期(“2009年11月解決”)或者一個(gè)特定的事件(“等到所有的客戶都可以處理XML請(qǐng)求就移除這些代碼”)

import導(dǎo)入格式

  • 每個(gè)導(dǎo)入應(yīng)該獨(dú)占一行

      推薦: import os       import sys
      不推薦:  import os, sys
    from flask import Flask, render_template, jsonify
  • 導(dǎo)入總應(yīng)該放在文件頂部, 位于模塊注釋和文檔字符串之后, 模塊全局變量和常量之前. 導(dǎo)入應(yīng)該按照從最通用到最不通用的順序分組:

    • 標(biāo)準(zhǔn)庫導(dǎo)入

    • 第三方庫導(dǎo)入

    • 應(yīng)用程序指定導(dǎo)入

  • 所有 import 盡量放在文件開頭,在 docstring 下面,其他變量定義的上面

  • 不要使用 from foo imort *

  • 為了避免可能出現(xiàn)的命名沖突,可以使用 as 或?qū)肷弦患?jí)命名空間

  • 不要出現(xiàn)循環(huán)導(dǎo)入(cyclic import)

命名

命名參考形式:
module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_VAR_NAME, instance_var_name, function_parameter_name, local_var_name.

  • 應(yīng)該避免的名稱

    • 單字符名稱, 除了計(jì)數(shù)器和迭代器.

    • 包/模塊名中的連字符(-)

    • 雙下劃線開頭并結(jié)尾的名稱(Python保留, 例如init)

  • 命名約定

    • 所謂”內(nèi)部(Internal)”表示僅模塊內(nèi)可用, 或者, 在類內(nèi)是保護(hù)或私有的.

    • 用單下劃線(_)開頭表示模塊變量或函數(shù)是protected的(使用import * from時(shí)不會(huì)包含).

    • 用雙下劃線(__)開頭的實(shí)例變量或方法表示類內(nèi)私有.

    • 將相關(guān)的類和頂級(jí)函數(shù)放在同一個(gè)模塊里. 不像Java, 沒必要限制一個(gè)類一個(gè)模塊.

    • 對(duì)類名使用大寫字母開頭的單詞(如CapWords, 即Pascal風(fēng)格), 但是模塊名應(yīng)該用小寫加下劃線的方式(如lower_with_under.py). 盡管已經(jīng)有很多現(xiàn)存的模塊使用類似于CapWords.py這樣的命名, 但現(xiàn)在已經(jīng)不鼓勵(lì)這樣做, 因?yàn)槿绻K名碰巧和類名一致, 這會(huì)讓人困擾.

  • 盡量單獨(dú)使用小寫字母'l’,大寫字母'O’等容易混淆的字母。

  • 模塊命名盡量短小,使用全部小寫的方式,可以使用下劃線。

  • 包命名盡量短小,使用全部小寫的方式。

  • 類的命名使用CapWords的方式,模塊內(nèi)部使用的類采用_CapWords的方式。

  • 異常命名使用CapWords+Error后綴的方式。

  • 全局變量盡量只在模塊內(nèi)有效,類似C語言中的static。實(shí)現(xiàn)方法有兩種,一是all機(jī)制;二是前綴一個(gè)下劃線。

  • 函數(shù)命名使用全部小寫的方式,可以使用下劃線。

  • 常量命名使用全部大寫的方式,可以使用下劃線。

  • 類的屬性(方法和變量)命名使用全部小寫的方式,可以使用下劃線。

  • 類的屬性有3種作用域public、non-public和subclass API,可以理解成C++中的public、private、protected,non-public屬性前,前綴一條下劃線。

  • 類的屬性若與關(guān)鍵字名字沖突,后綴一下劃線,盡量不要使用縮略等其他方式。

  • 為避免與子類屬性命名沖突,在類的一些屬性前,前綴兩條下劃線。比如:類Foo中聲明a,訪問時(shí),只能通過Foo._Fooa,避免歧義。如果子類也叫Foo,那就無能為力了。

  • 類的方法第一個(gè)參數(shù)必須是self,而靜態(tài)方法第一個(gè)參數(shù)必須是cls。

  • 使用有意義的,英文單詞或詞組,絕對(duì)不要使用漢語拼音

  • package/module 名中不要出現(xiàn) -

Main方法

  • 所有的頂級(jí)代碼在模塊導(dǎo)入時(shí)都會(huì)被執(zhí)行. 要小心不要去調(diào)用函數(shù), 創(chuàng)建對(duì)象, 或者執(zhí)行那些不應(yīng)該在使用pydoc時(shí)執(zhí)行的操作.

字符串

  • 使用字符串的 join 方法拼接字符串

  • 使用字符串類型的方法,而不是 string 模塊的方法

  • 使用 startswith 和 endswith 方法比較前綴和后綴

  • 使用 format 方法格式化字符串

比較

  • 空的 list, str, tuple, set, dict 和 0, 0.0, None 都是 False

  • 使用 if some_list 而不是 if len(some_list) 判斷某個(gè) list 是否為空,其他類型同理

  • 使用 is 和 is not 與單例(如 None)進(jìn)行比較,而不是用 == 和 !=

  • 使用 if a is not None 而不是 if not a is None

  • 用 isinstance 而不是 type 判斷類型

  • 不要用 == 和 != 與 True 和 False 比較(除非有特殊情況,如在 sqlalchemy 中可能用到)

  • 使用 in 操作:

  • 用 key in dict 而不是 dict.has_key()

      不推薦 if d.has_key(k):
      do_something()
    
      推薦 if key in d:
      do_something()
  • 用 set 加速 “存在性” 檢查,list 的查找是線性的,復(fù)雜度 O(n),set 底層是 hash table, 復(fù)雜度 O(1),但用 set 需要比 list 更多內(nèi)存空間

代碼編排

  • 縮進(jìn)。4個(gè)空格的縮進(jìn)(編輯器都可以完成此功能),不使用Tap,更不能混合使用Tap和空格。

  • 每行最大長度79,換行可以使用反斜杠,最好使用圓括號(hào)。換行點(diǎn)要在操作符的后邊敲回車。

  • 類和top-level函數(shù)定義之間空兩行;類中的方法定義之間空一行;函數(shù)內(nèi)邏輯無關(guān)段落之間空一行;其他地方盡量不要再空行。

文檔編排

  • 模塊內(nèi)容的順序:模塊說明和docstring—import—globals&constants—其他定義。其中import部分,又按標(biāo)準(zhǔn)、三方和自己編寫順序依次排放,之間空一行。

  • 不要在一句import中多個(gè)庫,比如import os, sys不推薦。

  • 如果采用from XX import XX引用庫,可以省略'module.’,都是可能出現(xiàn)命名沖突,這時(shí)就要采用import XX

編碼建議

  • 編碼中考慮到其他python實(shí)現(xiàn)的效率等問題,比如運(yùn)算符'+’在CPython(Python)中效率很高,都是Jython中卻非常低,所以應(yīng)該采用.join()的方式。

  • 盡可能使用'is’'is not’取代'==’,比如if x is not None 要優(yōu)于if x。

  • 使用基于類的異常,每個(gè)模塊或包都有自己的異常類,此異常類繼承自Exception。

  • 異常中不要使用裸露的except,except后跟具體的exceptions。

  • 異常中try的代碼盡可能少。

  • 使用startswith() and endswith()代替切片進(jìn)行序列前綴或后綴的檢查。比如:

    推薦:  if foo.startswith('bar'):
    不推薦:  if foo[:3] == 'bar':
  • 使用isinstance()比較對(duì)象的類型。比如

    推薦:  if isinstance(obj, int): 優(yōu)于
    不推薦:  if type(obj) is type(1):
  • 判斷序列空或不空,有如下規(guī)則

    Yes:  if not seq:if seq:
    優(yōu)于
    No:  if len(seq)if not len(seq)
  • 字符串不要以空格收尾。

  • 二進(jìn)制數(shù)據(jù)判斷使用 if boolvalue的方式。

  • 使用列表表達(dá)式(list comprehension),字典表達(dá)式(dict comprehension, Python 2.7+) 和生成器(generator)

  • dict 的 get 方法可以指定默認(rèn)值,但有些時(shí)候應(yīng)該用 [] 操作,使得可以拋出 KeyError

  • 使用 for item in list 迭代 list, for index, item in enumerate(list) 迭代 list 并獲取下標(biāo)

  • 使用內(nèi)建函數(shù) sorted 和 list.sort 進(jìn)行排序

  • 適量使用 map, reduce, filter 和 lambda,使用內(nèi)建的 all, any 處理多個(gè)條件的判斷

  • 使用裝飾器(decorator)

  • 使用 with 語句處理上下文

  • 使用 logging 記錄日志,配置好格式和級(jí)別

  • 閱讀優(yōu)秀的開源代碼,如 Flask 框架, Requests

  • 不要重復(fù)造輪子,查看標(biāo)準(zhǔn)庫、PyPi、Github、Google 等使用現(xiàn)有的優(yōu)秀的解決

好了,時(shí)間也不早了,今天就到此為止吧,如果覺得本文對(duì)你有點(diǎn)用的話,就邀請(qǐng)身邊的人關(guān)注起吧~

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多