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

Python 增强提案

PEP 7 – C 代码风格指南

作者:
Guido van Rossum <guido at python.org>, Barry Warsaw <barry at python.org>
状态:
活跃
类型:
流程
创建日期:
2001年7月5日
发布历史:


目录

引言

本文档提供了构成 Python C 实现的 C 代码的编码约定。请参阅描述 Python 代码风格指南的配套信息性 PEP。

请注意,规则就是用来打破的。打破特定规则的两个充分理由是:

  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 函数
    • 指定初始化器(特别适用于类型声明)
    • 混合声明
    • 布尔值
    • C++ 风格的行注释
  • Python 3.6 之前的版本使用 ANSI/ISO 标准 C(1989 年版标准)。这意味着,除其他许多事情外,所有声明都位于块的顶部。

常见 C 代码约定

  • 不要使用特定于编译器的扩展,例如 GCC 或 MSVC 的扩展。例如,不要在没有尾随反斜杠的情况下编写多行字符串。
  • 所有函数声明和定义都必须使用完整原型。也就是说,指定所有参数的类型,并使用 (void) 声明没有参数的函数。
  • 主要编译器(gcc、VC++、其他一些)没有编译器警告。
  • 新代码中应优先使用 static inline 函数而不是宏。

代码布局

  • 使用 4 个空格缩进,完全不使用制表符。
  • 任何一行都不应超过 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 文件局部宏。
  • 在函数、结构定义和函数内部的主要部分周围留空行。
  • 注释放在它们描述的代码之前。
  • 所有函数和全局变量都应声明为静态,除非它们是已发布接口的一部分。
  • 对于外部函数和变量,我们总是在“Include”目录中的适当头文件中有一个声明,该声明使用 PyAPI_FUNC() 宏和 PyAPI_DATA() 宏,如下所示:
    PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
    
    PyAPI_DATA(PyTypeObject) PySuper_Type;
    

命名约定

  • 公共函数使用 Py 前缀;静态函数从不使用。 Py_ 前缀保留用于全局服务例程,如 Py_FatalError;特定的例程组(例如特定对象类型 API)使用更长的前缀,例如字符串函数的 PyString_
  • 公共函数和变量使用混合大小写并带有下划线,例如:PyObject_GetAttrPy_BuildValuePyExc_TypeError
  • 有时“内部”函数必须对加载器可见;我们为此使用 _Py 前缀,例如:_PyObject_Dump
  • 宏应具有混合大小写前缀,然后使用大写,例如:PyString_AS_STRINGPy_PRINT_RAW
  • 宏参数应使用 ALL_CAPS 风格,以便它们易于与 C 变量和结构成员区分开来。

文档字符串

  • 使用 PyDoc_STR()PyDoc_STRVAR() 宏用于文档字符串,以支持在没有文档字符串的情况下构建 Python(./configure --without-doc-strings)。
  • 每个函数文档字符串的第一行应是“签名行”,简要概述参数和返回值。例如:
    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