PEP 7 – C 語言程式碼風格指南
- 作者:
- Guido van Rossum <guido at python.org>, Barry Warsaw <barry at python.org>
- 狀態:
- 作用中
- 類型:
- 流程
- 建立日期:
- 2001-07-05
- 公告歷史:
簡介
本文件提供了建構 Python C 實作的 C 程式碼編寫慣例。請參閱隨附的資訊性 PEP,其中描述了 Python 程式碼風格指南。
請注意,規則是用來打破的。打破特定規則的兩個正當理由:
- 當套用該規則會使程式碼的可讀性降低時,即使對習慣閱讀符合規範程式碼的人來說也是如此。
- 為了與周遭同樣違反該規則的程式碼保持一致(或許是出於歷史原因)——儘管這也是清理他人留下的混亂代碼的機會(秉持極限編程 XP 風格)。
C 標準
請遵循以下標準。對於相關標準中未涵蓋的功能,請使用 CPython 特有的封裝器(例如:_Py_atomic_store_int32、Py_ALWAYS_INLINE、Py_ARITHMETIC_RIGHT_SHIFT;以及公共標頭檔中的 _Py_ALIGNED_DEF)。在新增此類封裝器時,請嘗試使其易於針對不支援的編譯器進行調整。
- Python 3.11 及更新版本使用 C11 標準,但不包含 選擇性功能。公共 C API 應與 C99 和 C++ 相容。
(提醒閱讀此文的使用者:此 PEP 是一份「風格指南」;這些規則是用來打破的。)
- Python 3.6 到 3.10 使用 C89 標準,並包含部分精選的 C99 功能:
<stdint.h>和<inttypes.h>中的標準整數型別。我們要求使用固定寬度的整數型別。static inline函式- 指定初始化器(designated initializers,對於型別宣告特別好用)
- 混合宣告(intermingled declarations)
- 布林值(booleans)
- C++ 風格的行註解
- 3.6 之前的 Python 版本使用 ANSI/ISO 標準 C(1989 年版本)。這意味著,除其他事項外,所有宣告都必須放在區塊的最開頭。
通用 C 語言程式碼慣例
- 請勿使用編譯器特定的延伸功能,例如 GCC 或 MSVC 的功能。例如,請勿在沒有尾隨反斜線的情況下撰寫多行字串。
- 所有函式宣告和定義必須使用完整原型(full prototypes)。亦即,指定所有參數的型別,並使用
(void)來宣告無參數的函式。 - 主要編譯器(gcc、VC++ 及其他少數編譯器)不得產生任何編譯器警告。
- 在新的程式碼中,應優先使用
static inline函式而非巨集。
程式碼佈局
- 使用 4 個空格進行縮排,完全禁止使用 Tab。
- 每行不得超過 79 個字元。如果這條規則加上前一條規則讓您的程式碼編寫空間不足,則代表您的程式碼過於複雜——請考慮使用子常式。
- 行尾不得有空白。如果您認為自己需要顯著的尾隨空白,請三思——有些人的編輯器可能會習慣性地刪除它們。
- 函式定義風格:函式名稱置於第 1 行,最外層大括號置於第 1 行,區域變數宣告後留一行空白。
static int extra_ivars(PyTypeObject *type, PyTypeObject *base) { int t_size = PyType_BASICSIZE(type); int b_size = PyType_BASICSIZE(base); assert(t_size >= b_size); /* type smaller than base! */ ... return 1; }
- 程式碼結構:像
if、for等關鍵字與後方的左括號之間保留一個空格;括號內不得有空格;所有地方皆必須使用大括號,即使 C 語言允許省略時亦然,但不要在您未進行其他修改的既有程式碼中補上大括號。所有新的 C 程式碼皆要求使用大括號。大括號應按以下方式格式化:if (mro != NULL) { ... } else { ... }
- return 陳述式中不應有冗餘的括號
return(albatross); /* incorrect */
應改為
return albatross; /* correct */
- 函式與巨集呼叫風格:
foo(a, b, c)——左括號前無空格,括號內無空格,逗號前無空格,逗號後有一個空格。 - 在賦值、布林與比較運算子周圍務必加上空格。在使用多個運算子的表達式中,在最外層(優先級最低)的運算子周圍加上空格。
- 斷行長行:若可以,請在最外層參數列表的逗號後斷行。務必適當縮排續行,例如:
PyErr_Format(PyExc_TypeError, "cannot create '%.100s' instances", type->tp_name);
- 當您在二元運算子處中斷長表達式時,大括號應按以下方式格式化:
if (type->tp_dictoffset != 0 && base->tp_dictoffset == 0 && type->tp_dictoffset == b_size && (size_t)t_size == b_size + sizeof(PyObject *)) { return 0; /* "Forgive" adding a __dict__ only */ }
將運算子放在行尾是可以接受的,特別是為了與周遭程式碼保持一致。(詳細討論請參見 PEP 8。)
- 在多行巨集中垂直對齊行接續字元。
- 旨在作為陳述式使用的巨集,應使用
do { ... } while (0)巨集慣用法,且結尾不加分號。範例:#define ADD_INT_MACRO(MOD, INT) \ do { \ if (PyModule_AddIntConstant((MOD), (#INT), (INT)) < 0) { \ goto error; \ } \ } while (0) // To be used like a statement with a semicolon: ADD_INT_MACRO(m, SOME_CONSTANT);
- 使用後請
#undef檔案內部的區域巨集。 - 在函式、結構定義以及函式內的主要區段周圍留出空白行。
- 註解應放在其描述的程式碼之前。
- 所有函式和全域變數都應宣告為 static,除非它們是要公開的介面一部分。
- 對於外部函式和變數,我們始終在「Include」目錄中適當的標頭檔內進行宣告,並使用
PyAPI_FUNC()巨集和PyAPI_DATA()巨集,如下所示:PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); PyAPI_DATA(PyTypeObject) PySuper_Type;
命名慣例
- 公開函式請使用
Py前綴;static 函式則絕不使用。Py_前綴保留給全域服務常式,例如Py_FatalError;特定群組的常式(例如特定物件型別 API)使用較長的前綴,例如字串函式的PyString_。 - 公開函式與變數使用 MixedCase(混合大小寫)並加上底線,例如:
PyObject_GetAttr、Py_BuildValue、PyExc_TypeError。 - 有時「內部」函式必須對載入器可見;我們為此使用
_Py前綴,例如:_PyObject_Dump。 - 巨集應具有 MixedCase 前綴,後接大寫字母,例如:
PyString_AS_STRING、Py_PRINT_RAW。 - 巨集參數應使用
ALL_CAPS風格,以便輕鬆地與 C 變數及結構成員區分開來。
說明字串(Documentation Strings)
- 請使用
PyDoc_STR()或PyDoc_STRVAR()巨集來撰寫說明字串,以便支援在不含說明字串的情況下建構 Python(使用./configure --without-doc-strings)。 - 每個函式說明字串的第一行應為「簽名行」(signature line),簡要概述參數和回傳值。例如:
PyDoc_STRVAR(myfunction__doc__, "myfunction(name, value) -> bool\n\n\ Determine whether name and value make a valid pair.");
請務必在簽名行與描述文字之間保留一行空白。
如果函式沒有回傳值(回傳值始終為
None),則不需要包含回傳型別的說明。 - 撰寫多行說明字串時,請務必使用反斜線進行連接(如上例所示),或是使用字串字面值串接:
PyDoc_STRVAR(myfunction__doc__, "myfunction(name, value) -> bool\n\n" "Determine whether name and value make a valid pair.");
雖然某些 C 編譯器在兩者皆缺的情況下也能接受字串字面值,
/* BAD -- don't do this! */ PyDoc_STRVAR(myfunction__doc__, "myfunction(name, value) -> bool\n\n Determine whether name and value make a valid pair.");
但並非所有編譯器皆如此;已知 MSVC 編譯器會對此報錯。
版權
此文件已歸入公有領域 (public domain)。
來源:https://github.com/python/peps/blob/main/peps/pep-0007.rst