Following system colour scheme - Python 增強提案 Selected dark colour scheme - Python 增強提案 Selected light colour scheme - Python 增強提案

Python 增強提案 (Python Enhancement Proposals)

PEP 7 – C 語言程式碼風格指南

作者:
Guido van Rossum <guido at python.org>, Barry Warsaw <barry at python.org>
狀態:
作用中
類型:
流程
建立日期:
2001-07-05
公告歷史:


目錄

簡介

本文件提供了建構 Python C 實作的 C 程式碼編寫慣例。請參閱隨附的資訊性 PEP,其中描述了 Python 程式碼風格指南

請注意,規則是用來打破的。打破特定規則的兩個正當理由:

  1. 當套用該規則會使程式碼的可讀性降低時,即使對習慣閱讀符合規範程式碼的人來說也是如此。
  2. 為了與周遭同樣違反該規則的程式碼保持一致(或許是出於歷史原因)——儘管這也是清理他人留下的混亂代碼的機會(秉持極限編程 XP 風格)。

C 標準

請遵循以下標準。對於相關標準中未涵蓋的功能,請使用 CPython 特有的封裝器(例如:_Py_atomic_store_int32Py_ALWAYS_INLINEPy_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;
    }
    
  • 程式碼結構:像 iffor 等關鍵字與後方的左括號之間保留一個空格;括號內不得有空格;所有地方皆必須使用大括號,即使 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_GetAttrPy_BuildValuePyExc_TypeError
  • 有時「內部」函式必須對載入器可見;我們為此使用 _Py 前綴,例如:_PyObject_Dump
  • 巨集應具有 MixedCase 前綴,後接大寫字母,例如:PyString_AS_STRINGPy_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 編譯器會對此報錯。


來源:https://github.com/python/peps/blob/main/peps/pep-0007.rst

最後修改:2025-08-27 10:48:57 GMT