Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 7 – Style Guide for C Code

Author:
Guido van Rossum <guido at python.org>, Barry Warsaw <barry at python.org>
Status:
Active
Type:
Process
Created:
05-Jul-2001
Post-History:


Table of Contents

介绍

This document gives coding conventions for the C code comprising the C implementation of Python. Please see the companion informational PEP describing style guidelines for Python code.

注意,规则是用来被打破的。打破某项规则的两个好理由:

  1. 当应用该规则会使代码的可读性降低,即使是对于习惯于阅读遵循规则的代码的人来说。
  2. 要与周围的代码保持一致,这些代码也会破坏它(也许是出于历史原因)– 尽管这也是一个清理别人的烂摊子的机会(真正的 XP 风格)。

C 方言

  • Python 3.11 and newer versions use C11 without optional features. The public C API should be compatible with C++.
  • Python 3.6 to 3.10 use C89 with several select C99 features:
    • 标准整数类型在 <stdint.h><inttypes.h>。我们需要固定宽度的整数类型。
    • static inline 函数
    • 指定的初始化器(对类型声明来说特别好)
    • 混杂的声明
    • 布尔运算
    • C++ 风格的行注释
  • Python versions before 3.6 used ANSI/ISO standard C (the 1989 version of the standard). This meant (amongst many other things) that all declarations must be at the top of a block (not necessarily at the top of function).
  • Don’t use compiler-specific extensions, such as those of GCC or MSVC (e.g. don’t write multi-line strings without trailing backslashes).
  • 所有的函数声明和定义必须使用完整的原型(即指定所有参数的类型)。
  • 在主要的编译器(gcc、VC++ 和其他一些)中没有编译器警告。
  • static inline functions should be preferred over macros in new code.

代码布局

  • 使用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 albatross; /* correct */
    return(albatross); /* incorrect */
    
  • 函数和宏的调用方式: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 */
    }
    
  • 在函数、结构定义和函数内部的主要部分周围放上空行。
  • 注释放在其描述的代码之前。
  • 所有的函数和全局变量都应该被声明为静态的,除非它们将成为已发布的接口的一部分
  • For external functions and variables, we always have a declaration in an appropriate header file in the “Include” directory, which uses the PyAPI_FUNC() macro and PyAPI_DATA() macro, like this:
    PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
    
    PyAPI_DATA(PyTypeObject) PySuper_Type;
    

命名公约

  • 对公共函数使用 Py 前缀;对静态函数绝不使用。Py_ 前缀保留给全局服务例程,如 Py_FatalError;特定的例程组(如特定的对象类型 API)使用更长的前缀,如 PyString_ 用于字符串函数。
  • 公共函数和变量使用带下划线的 MixedCase,像这样:PyObject_GetAttrPy_BuildValuePyExc_TypeError
  • 有时候,一个 “internal” 函数必须对加载器可见;我们使用 _Py 前缀来表示,例如:_PyObject_Dump
  • 宏应该有一个 MixedCase 前缀,然后使用大写字母,例如:PyString_AS_STRINGPy_PRINT_RAW

文档字符串

  • 使用 PyDoc_STR()PyDoc_STRVAR() 宏来处理文档字符串,以支持在没有文档字符串的情况下构建 Python (./configure --without-doc-strings)。

    对于需要支持高于 2.3 版本的 Python 的 C 语言代码,你可以在包括 Python.h 之后包括这个

    #ifndef PyDoc_STR
    #define PyDoc_VAR(name)         static char name[]
    #define PyDoc_STR(str)          (str)
    #define PyDoc_STRVAR(name, str) PyDoc_VAR(name) = PyDoc_STR(str)
    #endif
    
  • 每个函数文档字符串的第一行应该是一个 “签名行”,给出参数和返回值的简要概述。比如说
    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 编译器会抱怨这一点。


Source: https://github.com/python/peps/blob/main/pep-0007.txt

Last modified: 2022-05-17 18:51:40 GMT