首頁  >  文章  >  後端開發  >  Python編碼格式的詳細介紹(附範例)

Python編碼格式的詳細介紹(附範例)

不言
不言轉載
2019-01-28 10:56:453614瀏覽

本篇文章帶給大家的內容是關於Python編碼格式的詳細介紹(附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

程式碼除了用來運行外,更多的是用來讀。為了是程式碼的可讀性更強,許多程式語言都有自己的編碼規格。規範的製定是為了保持代碼的一致性,以使代碼更美觀和易讀。程式碼應該怎麼樣排版和編寫並不是絕對的,所以有些地方會有爭議。有時風格指南並不適用,最重要的知道何時不一致。當你無法判斷該怎麼做時,應該所參考下其他的例子。

本文僅是一個 Python 編碼風格的參考,並不是一個規定,規定必須要這麼做。本文的目的應該是起一個指導作用,指導開發者寫更易讀的程式碼。

一、程式碼編排

主要是縮排與空白行的排版:

  • 1、使用4 個空格進行縮排(編輯器都可以完成此功能),不建議使用製表符,更不能混合使用製表符和空格。

  • 2、每行不超過80 個字符,換行可以使用反斜杠,最好使用括號(Python 會將圓括號, 中括號和花括號中的行隱式的連接起來)。

  • 3、類別和頂層函數定義之間空兩行;類別中的方法定義之間空一行;函數內邏輯無關段落之間空一行;其他地方盡量不要再空行。

主要是整個原始碼檔案的版面:

  • #1、模組內容的順序:模組說明,模組文件字串,導入語句,全域變數或常數,其他定義。

  • 2、模組導入部分順序:標準函式庫,第三方模組,自訂模組;各部分之間空一行。

  • 3、不要在一個 import 語句中一次導入多個模組,例如 import os, sys 不建議。

  • 4、導入模組時應該使用適當的方式來避免命名衝突,例如在適當的時候才使用from xx import xx,盡量避免使用from xx imoprt *

  • 5、在自已編寫的模組中,如果需要使用from xx import * 時,應該在導入語句後或模組尾使用__all__ 機制來限制匯入規則。

三、語句編排

  • 1、通常每個語句應該獨佔一行。

  • 2、不要在行尾加分號, 也不要用分號將多條語句放在同一行。

  • 3、if/for/while 語句中,即使執行語句只有一句,也應盡量另起一行。

  • 4、不要在回傳語句(return)或條件語句(if/for/while)中使用括號,除非是用來實現行連接。

  • 5、對於if 語句, 在沒有else 且語句比較短時,可以在一行完成(但不建議),例如:if foo: bar(foo).

  • 6、對於簡單的類別定義,也可以在一行中完成(但不建議),例如定義一個例外:class UnfoundError(Exception): pass.

  • 7、函數和方法的括號中使用垂直隱式縮排或使用懸掛縮排。

# 一行写不下时,有括号来连接多行,后续行应该使用悬挂缩进
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

# 函数调用参数较多时,对准左括号
f = foo(a, b,
        c, d)

# 不对准左括号,但加多一层缩进,以和后面内容区别
def long_function_name(
        a, b, c,
        d, e):
    print(a, b, c, d, e)

# 列表、元组、字典以及函数调用时可以让右括号回退,这样更加美观
l = [
    1, 2, 3,
    4, 5, 6,
]

result = some_function(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

四、空格使用

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

  • 1、各種右括號前不要加空格。

  • 2、逗號、冒號、分號前不要加空格,但應該在它們後面加(除了在行尾)。

  • 3、函數的左括號前不要加空格。如 Func(1)。

  • 4、序列的左括號前不要加空格。如 list[2]。

  • 5、運算元左右各加一個空格,不要為了對齊增加空格。

  • 6、函數預設參數使用的賦值符號左右省略空格。

良好的風格:

spam(ham[1], {eggs: 2})

if x == 4:
    print x, y; x, y = y, x

f = foo(1, 2, 3)

ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]

x = 1
y = 2
long_variable = 3

def foo(a, b, c=0):
    return moo(m=a, n=b, o=c)

不好的風格:

spam( ham[ 1 ], { eggs: 2 } )

if x == 4 :
    print x , y ; x , y = y , x

f = foo (1, 2, 3)

ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]

x             = 1
y             = 2
long_variable = 3

def foo(a, b, c = 0):
    return moo(m = a, n = b, o = c)

五、註解

整體原則,錯誤的註釋不如沒有註解。所以當一段程式碼改變時,第一件事就是要修改註解。註釋盡量使用英文,最好是完整的句子,首字母大寫,句後面要有結束符,結束符後跟兩個空格,開始下一句。如果是短語,可以省略結束符號。註解應該在 # 後面加上一個空格才開始寫註解內容。

  • 1、區塊註釋,在一段程式碼前面增加的註釋。段落之間用只有 ‘#’ 的行間隔。例如:

# Description : Module config.
#
# Input : None
#
# Output : None
  • 2、行註釋,在一句程式碼後面加上註解。應該盡量在語句後空兩格後再開始註解。當有連續的行註解時,為了美觀可以讓 ‘#’ 對齊。在語句比較長時,應該盡量少使用行註解。如:

person = {
    "name": "huoty",  # 姓名
    "age": 26,        # 年龄
    "stature": 169,   # 身高
    "weight": 60,     # 体重
}

print person  # 输出信息
  • 3、对类或者函数的说明,尽量不要在其定义的前一行或者后一行用块注释的形式来说明,而应该使用文档字符串(docstring)

  • 4、使用 TODO 注释来标记待完成的工作,团队协作中,必要的时候应该写上你的名字或者联系方式,比如:

# TODO(sudohuoty@gmail.com): Use a "*" here for string repetition.
# TODO(Huoty) Change this to use relations.
  • 5、避免无谓的注释。你见过哪些奇趣的代码注释?

# 你可能会认为你读得懂以下的代码。但是你不会懂的,相信我吧。  

# 要是你尝试玩弄这段代码的话,你将会在无尽的通宵中不断地咒骂自己为什么会认为自己聪明到可以优化这段代码。  
# so,现在请关闭这个文件去玩点别的吧。  

# 程序员1(于2010年6月7日):在这个坑临时加入一些调料  
# 程序员2(于2011年5月22日):临你个屁啊  
# 程序员3(于2012年7月23日):楼上都是狗屎,鉴定完毕  
# 程序员4(于2013年8月2日):fuck 楼上,三年了,这坑还在!!!  
# 程序员5(于2014年8月21日):哈哈哈,这坑居然坑了这么多人,幸好我也不用填了,系统终止运行了,you're died

六、文档描述

  • 1、尽量为所有的共有模块、函数、类、方法写 docstring

  • 2、前三引号后不应该换行,应该紧接着在后面概括性的说明模块、函数、类、方法的作用,然后再空一行进行详细的说明。后三引号应该单独占一行。比如:

"""Convert an API path to a filesystem path

If given, root will be prepended to the path.
root must be a filesystem path already.
"""
  • 2、函数和方法的 docstring 层次顺序大致为概述、详细描述、参数、返回值、异常,一般不要求描述实现细节,除非其中涉及非常复杂的算法。大致的层次结构如下所示:

"""函数或方法的概述

详细的描述信息……
详细的描述信息……

参数说明
--------
    参数1:...
    参数2:...

返回值:
    ...

异常:
    异常1:...
    异常2:...
"""

一个参考示例:

"""Start a kernel for a session and return its kernel_id.                                                                                             

Parameters
----------
kernel_id : uuid
    The uuid to associate the new kernel with. If this
    is not None, this kernel will be persistent whenever it is
    requested.
path : API path
    The API path (unicode, '/' delimited) for the cwd.
    Will be transformed to an OS path relative to root_dir.
kernel_name : str
    The name identifying which kernel spec to launch. This is ignored if
    an existing kernel is returned, but it may be checked in the future.

Return a kernel id
"""
  • 3、类的 docstring 的层次顺序大致为概述、详细描述、属性说明。如果类有公开属性值时,应该尽量在 docstring 中进行说明。如下所示:

"""这里是类的概述。

详细的描述信息……
详细的描述信息……

属性(Attributes):
-----------------
    属性1: ...
    属性2: ...
"""

七、命名规范

  • 1、模块命名尽量短小,使用全部小写的方式,可以使用下划线。

  • 2、包命名尽量短小,使用全部小写的方式,不可以使用下划线。

  • 3、类的命名使用驼峰命令的方式,即单词首字符大写,类名应该全部使用名词。

  • 4、异常命令应该使用加 Error 后缀的方式,比如:HTTPError。

  • 5、全局变量尽量只在模块内有效,并且应该尽量避免使用全局变量。

  • 6、函数命名使用全部小写的方式,使用下划线分割单词,并采用动宾结构。

  • 7、常量命名使用全部大写的方式,使用下划线分割单词。

  • 8、类的属性(方法和变量)命名使用全部小写的方式,使用下划线分割单词。

  • 9、变量、类属性等命令尽量不要使用缩写形式,除了计数器和迭代器,尽量不要使用单字符名称。

  • 10、类的方法第一个参数必须是 self,而静态方法第一个参数必须是 cls。

  • 11、在模块中要表示私有变量或者函数时,可以在变量或者函数前加一个下划线 _foo, _show_msg 来进行访问控制。

  • 12、在 Python 中没有诸如 public、private、protected 等修饰符,而在类的定义中往往会有类似这样的需求,那么可以在属性或者方法前加一个下划线表示 protected,加两个下划线来表示 private。加两个下划线的变量或者方法没法直接访问。比如:类 Foo 中声明 __a, 则不能用 Foo.__a 的方式访问,但可以用 Foo._Foo__a 的方式访问。`

八、程序入口

Python 属于脚本语言,代码的运行是通过解释器对代码文件进行逐行解释执行来完成的。它不像其他编程语言那样有统一的入口程序,比如 Java 有 Main 方法,C/C++ 有 main 方法。Python 的代码文件除了可以被直接执行外,还可以作为模块被其他文件导入。所有的顶级代码在模块导入时都会被执行,当希望模块被导入时,应该避免主程序被执行。这样就需要把主程序放到 if __name__ == '__main__' 代码块中,比如:

def main():
      ...

if __name__ == '__main__':
    main()

一个包除了能够被导入外,也可以通过 python -m package 的方式被直接执行,前提是包中需要有 __main__.py,这个文件可以说是包的程序入口,包中有了这个文件就可以用 Python 的 -m 参数来直接运行。

九、编码建议

  • 1、尽可能使用 'is' 和 'is not' 取代 '==',比如 if x is not None 要优于 if x != None,另外用 if x 效率更高。

Note: 等于比较运算符(==) 会调用左操作数的 __eq__ 函数,这个函数可以被其任意定义,而 is 操作只是做 id 比较,并不会被自定义。同时也可以发现 is 函数是要快于等于运算符的,因为不用查找和运行函数。

  • 2、用 "is not" 代替 "not ... is",前者的可读性更好。

  • 3、使用基于类的异常,每个模块或包都有自己的异常类,此异常类继承自 Exception。

  • 4、异常中尽量不要使用裸露的 except,except 后应该跟具体的 exceptions。

  • 5、使用 startswith() 和 endswith() 代替切片进行序列前缀或后缀的检查。

  • 6、使用 isinstance() 比较对象的类型,而不是 type(),比如:

# Yes:  
if isinstance(obj, int)

# No:  
if type(obj) is type(1)
  • 7、判断序列是否为空时,不用使用 len() 函数,序列为空时其 bool 值为 False,比如:

# Yes:  
if not seq
if seq

# No:  
if len(seq)
if not len(seq)
  • 8、字符串后面不要有大量拖尾空格。

  • 9、使用 join 合并的字符串,字符串方法 join 可以合并 list、tuple、iterator 中的元素,效率比连接符 + 高。

  • 10、使用 while 1while True 更快。

  • 11、使用 **pow 快 10 倍以上。

  • 12、使用迭代器和生成器代替列表等数据结构效率更高,使用列表(字典)解析式和生成器表达式比用循环效率更高。

  • 13、避免在循环中用 + 或 += 来连续拼接字符串。因为字符串是不变型,这会毫无必要地建立很多临时对象,从而成为二次方级别的运算量而不是线性运算时间。

  • 14、多去了解标准库,标准库中用很多好用的功能,能够更优雅的解决问题,如 pkgutil.get_data()、operator.methodcaller() 等等。


以上是Python編碼格式的詳細介紹(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除