当前位置:首页 > 运维 > 正文内容

PEP8 PYTHON 編碼規範手冊

MuWind7个月前 (10-24)运维69

PEP 8 介紹

PEP8 是 Python 社群共通的風格指南,一開始是 Python 之父 Guido van Rossum 自己的撰碼風格,慢慢後來演變至今,目的在於幫助開發者寫出可讀性高且風格一致的程式。許多開源計畫,例如 Django 、 OpenStack等都是以 PEP8 為基礎再加上自己的風格建議。

程式碼編排 (Code lay-out)

這邊列出PEP8裡面的重點,有興趣可以直接看官方原文的文件會更清楚一些。

縮排 (Indentation)
每層縮排使用 4 個空格

斷行風格
正確:
# 斷行首字母與開頭的括號垂直對齊.

1
2
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# 垂直縮排,首行不能有參數.

1
2
3
4
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# 垂直縮排,後面還有其它代碼時,需要添加一層額外的縮排加以區別:

1
2
3
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)

錯誤:
# 垂直縮排方式首行不能有引數

1
2
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# 垂直縮排,首行不能有參數; 後面還有其它代碼部分時,斷行要添加一層縮進,使其與其它代碼部分能區別開來

1
2
3
4
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

if 條件斷行
if ( 剛好有 4 個字符,相當於一層縮排。
對於 if 條件斷行,以下幾種風格都可以:
沒有額外的縮排

1
2
3
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

添加註釋加以區分

1
2
3
4
5
6
# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

添加額外的縮排加以區分

1
2
3
4
# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

多行的括號

括號結束符與最後行的首字符對齊,如:

1
2
3
4
5
6
7
8
9
my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
 
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

括號結束符與首行的首字符對齊, 如:

1
2
3
4
5
6
7
8
my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

上面兩種排版的方式都可以

使用Tab還是空格縮排

用空格

每行最長長度

所有行都不超過 80 個字符

限制編輯器視窗的寬度,使能並排同時打開多個文件。
設置編輯器寬度(set width to 80),來避免 wrapping
對於較少結構限制的長文本(如 docstrings 或註釋),行長應限制為 72 個字符。
如果團隊成員都同意使用長行,則可以將行長增加到不超過 100 個字符,但是 docstrings 和註釋還必須為 72 個字符。

有括號的長行可以用 implicit continuation 來斷行,其它的可以用 \ 來斷行,如:

1
2
3
with open('/path/to/some/file/you/want/to/read') as file_1, \
     open('/path/to/some/file/being/written', 'w') as file_2:
    file_2.write(file_1.read())

操作符要和操作數在一起

# 推薦的正確的風格,這樣很容易將操作符與操作數匹配:

1
2
3
4
5
income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

# 這種風格現今已不推薦使用了:

1
2
3
4
5
income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction -
          student_loan_interest)

空行分隔

模組中最頂層的函數和類定義都要用兩行空行分隔
類別中的方法定義用單行分隔
要把一組相關的函數分組,可以用一些額外的空行
函數中的邏輯區塊可以加空行來分隔

原始碼的編碼

Python 核心模組文件的編碼都必須用 UTF-8(Python2 是 ASCII)。
使用默認的編碼時(Python3: UTF-8,Python2: ASCII),不能使用編碼聲明
標準庫中,只有測試、作者名才能使用非默認的編碼,其它情況下的非 ASCII 字符用 \x, \u, \u, \N 表示法表示。

Import

每行 import 只導入一個模組:
# 正確:
import os
import sys
# 錯誤:
import sys, os
# 正確:同一模組中的內容可以在同一行導入
from subprocess import Popen, PIPE

import 語句要在文件的前面,在模組註釋及 docstrings 之後,在模組全域變數和常數定義之前。
import 分組及導入順序,每個分組之間用一行空行分隔 1. 標準庫 2. 相關第三方庫 3. 本地應用/庫的特殊導入
推薦使用絕對導入,如:
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example

在比較覆雜的套件組成中,也可以用顯式的相對導入,如:
from . import sibling
from .sibling import example
從一個模塊中導入一個類別時,要顯示拼寫出類別名,如:
from myclass import MyClass
from foo.bar.yourclass import YourClass

如果與本地名稱衝突,可以先導入模組:
import myclass
import foo.bar.yourclass
然後使用:"myclass.MyClass" 和 “foo.bar.yourclass.YourClass"。
應該避免使用 from <module> import *
模組層級的特殊名稱(如__all__)的位置:
必須在模組的 docstrings 或註釋之後,但在任何的 import 語句之前。from __future__ 比較特殊,Python 強制該語句必須在 docstrings 或註釋之後,因此風格如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
"""This is the example module.
 
This module does stuff.
"""
 
from __future__ import barry_as_FLUFL
 
__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'
 
import os
import sys

字符引號 (String Quotes)

單引號和雙引號的功能是等同的。
對於多行字符串,應該用雙引號字符形式的三引號""",以便與 PEP257 中的 docstrings 規範兼容

表達式和語句中的空格 (Whitespace in Expressions and Statements)

()、[]、{} 等括號內不要多餘的空格,如:
# 正確:
spam(ham[1], {eggs: 2})
# 錯誤:
spam( ham[ 1 ], { eggs: 2 } )
,、;、: 之前不要有空格,如:
# 正確:
if x == 4: print x, y; x, y = y, x
# 錯誤:
if x == 4 : print x , y ; x , y = y , x
在 slice 語句中的 :實際上是一個二元操作符,因此其兩側的空格數必須相同; 但當無 slice 參數時,兩側的空格可以都省略,如:
# 以下是正確的風格:
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]
# 以下是錯誤的風格:
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]
函數調用的 () 及索引的 [] 前不要加空格,如:
# 正確風格:
spam(1)
dct[‘key’] = lst[index]
# 錯誤風格:
spam (1)
dct [‘key’] = lst [index]
不要在賦值語句中加入額外的空格來對齊,如:
# 正確的風格:
x = 1
y = 2
long_variable = 3
# 錯誤的風格:
x = 1
y = 2
long_variable = 3

其它推薦風格

任何行的行尾都不要有空白符。
在二元操作符號兩側一般都要加一個空格,一般的二元操作符號如:
賦值: =, +=, -=
比較:==, <, >, !=, <>, <=, >=, in, not in, is, is not
布林操作: and, or, not
在分優先級的表達式中,在最低優先級的操作符兩側加一個空格,但至多只能加一個空格,如:
# 正確的風格:
x = x*2 – 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
# 錯誤的風格:
x = x * 2 – 1
hypot2 = x * x + y * y
c = (a + b) * (a – b)
在關鍵字參數和默認參數值中的 = 兩側不要加空格,如:
# 正確的風格:
def complex(real, imag=0.0):
return magic(r=real, i=imag)
錯誤的風格:
def complex(real, imag = 0.0):
return magic(r = real, i = imag)
函數註解中的 : 前不要加空格,這符合 : 的常規風格,但是 -> 兩側要加空格,如:
# 正確的風格:
def munge(input: AnyStr): …
def munge() -> AnyStr: …
# 錯誤的風格:
def munge(input:AnyStr): …
def munge()->PosInt: …
參數註解中,如果註解的參數有默認值,指定默認值的 = 兩側要加空格,如:
# 正確的風格:
def munge(sep: AnyStr = None): …
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): …
# 錯誤的風格:
def munge(input: AnyStr=None): …
def munge(input: AnyStr, limit = 1000): …

不要將多條語句組合在一行中,如:
# 正確的風格:
if foo == ‘blah’:
do_blah_thing()
do_one()
do_two()
do_three()
# 錯誤風格:
if foo == ‘blah’: do_blah_thing()
do_one(); do_two(); do_three()

# 如果 if/for/while 區塊內的程式碼很少,組合在一行有時還是可以接受的
# 但是不推薦,如:
if foo == ‘blah’: do_blah_thing()
for x in lst: total += x
while t < 10: t = delay()
# 但是在有多段語句時,絕對不能這樣,如:
if foo == ‘blah’: do_blah_thing()
else: do_non_blah_thing()

try: something()
finally: cleanup()

do_one(); do_two(); do_three(long, argument,
list, like, this)

if foo == ‘blah’: one(); two(); three()

註解 (Comments)

註解內容必須要和程式碼相關!
註解應該是完整的語句,首字母一般大寫(英文),一般要有句號。
註解很短時句號可以省略。
區塊註解一般由多個段落組成。用英文寫註解

區塊註解 (Block Comments)

每行用 # 及一個空格開始,如 #
段落用一個只有 # 的行分隔

行內註解 (Inline Comments)

註解與語句內容至少用兩個空格分開,註解用 # 加一個空格開始
# 不要像下面這樣,註解內容沒有必要
x = x + 1 # Increment x
# 但是有時,如下面的註解會很有用
x = x + 1 # Compensate for border

文件字串 (Documentation Strings)

公開的模組、函數、類及方法都應該有文件字串,而非公開的方法可以用註解來代替,且註解放置在 def 行之後。
多行的文件字串,結束符號要自成一行,如:

1
2
3
4
"""Return a foobang
 
Optional plotz says to frobnicate the bizbaz first.
"""

單行的文件字串,結束符號和內容放在同一行

命名 (Naming Conventions)

沒有推薦的風格,但是別人要能從你的程式碼中看出你用的是什麽風格,常用的風格如下:

  • b 單個小寫字母

  • B 單個大寫字母

  • lowercase

  • lower_case_with_underscores

  • UPPERCASE

  • UPPER_CASE_WITH_UNDERSCORES

  • CapitalizedWords, 這種風格中,對於縮寫詞應全部用大寫,如

  • HTTPServerError 比 HttpServerError 好

  • mixedCase
    Capitalized_Words_With_Underscores,這個太醜,不要用這種!

  • st_mode、st_mtime 等前綴,一般是系統接口返回,如果自己寫的程式碼不推薦用這種

  • _single_leading_underscore : 弱 “內部使用” 指示器,這種對象用 from M import * 不會被導入

  • single_trailing_underscore_ : 可以用來和 Python 關鍵詞進行區分,如 Tkinter.Toplevel(master, class_=’ClassName’)

  • __double_leading_underscore : 命名一個類屬性時,可以進行命名矯正,例如 class FooBar 內的 __boo 會變成 _FooBar__boo

  • double_leading_and_trailing_underscore : “magic” 對象,不要自己發明這種對象

命名習慣 (Prescriptive: Naming Conventions)

  • 不用單個 l, O, I 等這樣的單個字符來命名,它們與數字1,0不好區分

  • 套件名和模組名:全部用小寫,必要時可用 _,但不推薦,C/C++ 的擴展模組,如果其對應有 Python 版本,那麽 C/C++ 擴展模組名前加 _

  • 類別名:用 CapWords 風格

  • 異常名:用 CapWords 風格,一般應該有 Error 後綴

  • 全域變數名:能用 from M import * 導入的變數全部放在 __all__ 中,或者全域變數用 _ 做前綴

  • 函數名:應該用全部用小寫,單詞間可以用 _ 分隔,如 my_func,不推薦用 mixedCase 風格

  • 函數和方法的參數:實例方法的第一個參數用 self, 類別方法的第一個參數用 cls,如果參數與關鍵字衝突,在參數名後加 _ 後綴,如 class_

  • 實例變數和方法: 用小寫字符和 _, 非公開的實例變數和方法用一個 _ 做前綴; 避免與子類別中的名字衝突,類的變數可用兩個 _ 作前綴,例如 class FooBar 內的 __boo 會變成只能通過 FooBar._FooBar__boo 讀取

  • 常數:全部大寫,可用 _ 分隔,如 MAX_OVERFLOW、TOTAL

推薦的程式撰寫方式 (Programming Recommendations)

字符串連接不要用 a += b 或者 a = a + b, 用 “.join(), 後者性能更好。跟 None 的比較用 is 和 is not,不要用 ==,如果你想判斷 if x is not None, 不要縮寫成 if x 使用 if foo is not None,而不是 if not foo is None,前者更加易讀

如果要實現序列比較操作的話,應將 6 個操作(__eq__ , __ne__ , __lt__ , __le__ , __gt__ , __ge__)全部實現,可以借助 functools.total_ordering() 修飾器來減少工作量

將函數保存在一個變數中應該用 def f(x): return 2*x, 而非 f = lambda x: 2*x,後者不利於調試

自定義的異常類應該繼承至 Exception 類,而非 BaseException 類。Python 2 中拋出異常用 raise ValueError(‘message’),而非 raise ValueRoor, ‘message’

盡量可以的指明異常名,如:

1
2
3
4
try:
    import platform_specific_module
except ImportError:
    platform_specific_module = None

避免使用無異常名的 except: 語句,它會捕獲全部的異常(如 Ctrl C)。
將異常綁定到名字的方法:

1
2
3
4
try:
    process_data()
except Exception as exc:
    raise DataProcessingFailedError(str(exc))

try: 中的語句要盡量減少,如:
# 正確的寫法:

1
2
3
4
5
6
try:
    value = collection[key]
except KeyError:
    return key_not_found(key)
else:
    return handle_value(value)

# 錯誤的寫法

1
2
3
4
5
6
try:
    # Too broad!
    return handle_value(collection[key])
except KeyError:
    # Will also catch KeyError raised by handle_value()
    return key_not_found(key)

如果資源只適用於某個代碼段內,使用 with 或 try/finally 來確保能進行清理工作
上下文管理器應用通過一個單獨的函數或方法來呼叫,如:
# 正確的做法:

1
2
with conn.begin_transaction():
    do_stuff_in_transaction(conn)

# 錯誤的做法:

1
2
with conn:
    do_stuff_in_transaction(conn)

return 語句應該一致,如:
# 正確的做法:

1
2
3
4
5
6
7
8
9
10
def foo(x):
    if x &amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;= 0:
        return math.sqrt(x)
    else:
        return None
 
def bar(x):
    if x &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt; 0:
        return None
    return math.sqrt(x)

# 錯誤的做法:

1
2
3
4
5
6
7
8
def foo(x):
    if x &amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;= 0:
        return math.sqrt(x)
 
def bar(x):
    if x &amp;amp;amp;amp;amp;amp;amp;amp;amp;lt; 0:
        return
    return math.sqrt(x)

使用字符串的方法,而不是用 string 模組中的方法
使用 “.startswith() 和 “.endswidth() 而不用 slicing 來檢查前綴和後綴:
# 正確:
if foo.startswith(‘bar’):
# 錯誤:
if foo[:3] == ‘bar’:
判斷對象的類型用 isinstance 而不直接 type 比較,如:
# 正確:
if isinstance(obj, int):
# 錯誤:
if type(obj) is type(1):
對序列是否空的判斷不用 len,如:
# 正確:
if not seq:
if seq:
# 錯誤:
if len(seq):
if not len(seq):
布林值的比較:
# 正確:
if greeting:
# 不要這樣:
if greeting == True:
# 這樣更不行:
if greeting is True:


标签: pep8python

“PEP8 PYTHON 編碼規範手冊” 的相关文章

centos分区挂载磁盘

centos分区挂载磁盘

准备建个nas服务,大容量的硬盘是必不可少的。去经理那拿了块4T的硬盘,以后有需要我再加吧。硬盘硬件上的安装很简单,插两根线拧螺丝就行了。接下来说的是挂到系统先查看一下盘子是不是安装上了:fdisk -l但凡眼睛没问题的 都能找到自己那块新装的盘:连着按一个N键和三个p键就行然后格式化:m...

Zerotier配合Nginx实现内网穿透

Zerotier配合Nginx实现内网穿透

之前博客网站一直用的家里机器配合香港Azure做frp内网穿透,用CF CDN进行数据分发,不提frp的虚拟局域网模式在跨国数据传输时面临的数据审查和路由方向会给速度及稳定性造成非常大的影响,其可能有的内存溢出和服务重启时的持续掉线问题也是很抓狂的,在这里,使用zerotier为两机打洞连接p2p,...

CentOS Python后台运行

nohup python /data/python/server.py > python.log3 2>&1 &说明:1、1是标准输出(STDOUT)的文件描述符,2是标准错误(STDERR)的文件描述符 &nb...

yarn构建提示Error: error:0308010C:digital envelope routines::unsupported的解决方法

yarn构建提示Error: error:0308010C:digital envelope routines::unsupported的解决方法

这个是SSL套件的问题,输入下面的指令切换一下就好了:$env:NODE_OPTIONS = "--openssl-legacy-provider"...

记录一个远古垃圾系统的维护

记录一个远古垃圾系统的维护

这次接手的是tp框架的远古收款系统,开局几个ajax认不上我已经习以为常了,反手把php版本改成7.0就恢复正常(7.0算是个兼容版本 5.x的和7.x都兼容一点 各位穷途末路了可以试试)然后呢,其他的确认过没啥毛病了,打算测试一下接口的时候,意外就来了,弹404。我知道tp框架弹404一定是代码的...

雨云CDN清除指定文件的缓存

雨云CDN清除指定文件的缓存

雨云的CDN并没有给用户清除缓存的选项,想清除缓存的话其实挺麻烦的。通过浏览器对网站的请求头我们可以看到,CDN的服务器是apache apisix通过查阅apisix有关缓存的文档,我们可以发现清除缓存的方法:https://apisix.apache.org/zh/docs/apisix/2.1...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。