Python编程风格指南 python-style-guide

提供基于Google Python风格指南的全面Python编程指导原则,涵盖语言规则、风格规则和最佳实践,旨在实现清晰、可维护的代码。

后端开发 0 次安装 0 次浏览 更新于 3/2/2026

Python编程风格指南

基于Google的Python风格指南的全面的Python编程指导原则。当Claude需要编写Python代码、审查Python代码风格问题、重构Python代码或提供Python编程指导时使用。涵盖语言规则(导入、异常、类型注释)、风格规则(命名约定、格式化、文档字符串)以及最佳实践,以实现清晰、可维护的Python代码。

核心理念

保持一致性。 与你周围的代码风格相匹配。使用这些指导原则作为默认值,但始终优先考虑与现有代码的一致性。

语言规则

导入

仅对包和模块使用import语句,不要针对单个类或函数。

正确:

from doctor.who import jodie
import sound_effects.utils

错误:

from sound_effects.utils import EffectsRegistry  # 不要直接导入类

导入格式

  • 分组导入:标准库、第三方库、应用程序特定
  • 在每个组内按字母顺序排列
  • 使用绝对导入(不是相对导入)
  • 每行一个导入(typingcollections.abc中的多个项目除外)
# 标准库
import os
import sys

# 第三方库
import numpy as np
import tensorflow as tf

# 应用程序特定
from myproject.backend import api_utils

异常

适当使用异常。不要使用裸except:子句来抑制错误。

正确:

try:
    result = risky_operation()
except ValueError as e:
    logging.error(f"Invalid value: {e}")
    raise

错误:

try:
    result = risky_operation()
except:  # 太宽泛,隐藏错误
    pass

类型注释

为所有函数签名添加注释。类型注释提高了代码可读性并在早期捕获错误。

一般规则:

  • 为所有公共API添加注释
  • 使用内置类型(listdictset)而不是typing.List等。(Python 3.9+)
  • 直接导入typing符号:from typing import Any, Union
  • 使用None而不是type(None)NoneType
def fetch_data(url: str, timeout: int = 30) -> dict[str, Any]:
    """从URL获取数据。"""
    ...

def process_items(items: list[str]) -> None:
    """处理项目列表。"""
    ...

默认参数值

不要在函数定义中使用可变对象作为默认值。

正确:

def foo(a: int, b: list[int] | None = None) -> None:
    if b is None:
        b = []

错误:

def foo(a: int, b: list[int] = []) -> None:  # 可变默认值 - 错误!
    b.append(a)

真/假评估

尽可能使用隐式假。空序列、None0在布尔上下文中为假。

正确:

if not users:  # 首选
if not some_dict:
if value:

错误:

if len(users) == 0:  # 冗长
if users == []:
if value == True:  # 永远不要显式与True/False比较

推导式和生成器

对于简单情况,使用推导式和生成器。保持它们易于阅读。

正确:

result = [x for x in data if x > 0]
squares = (x**2 for x in range(10))

错误:

# 太复杂
result = [
    x.strip().lower() for x in data 
    if x and len(x) > 5 and not x.startswith('#')
    for y in x.split(',') if y
]  # 使用常规循环代替

Lambda函数

仅对单行代码使用lambda。对于任何复杂情况,请定义适当的函数。

正确:

sorted(data, key=lambda x: x.timestamp)

可接受,但更喜欢命名函数:

def get_timestamp(item):
    return item.timestamp

sorted(data, key=get_timestamp)

风格规则

行长度

最大行长度:80个字符。对于导入、URL和无法拆分的长字符串,允许例外。

缩进

每个缩进级别使用4个空格。永远不要使用制表符。

对于悬挂缩进,将包装的元素垂直对齐或使用4个空格的悬挂缩进:

# 与开头分隔符对齐
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# 悬挂缩进(4个空格)
foo = long_function_name(
    var_one, var_two, var_three,
    var_four)

空白行

  • 顶级定义之间两个空白行
  • 方法定义之间一个空白行
  • 在函数内适当使用空白行以显示逻辑部分

命名约定

类型 约定 示例
包/模块 lower_with_under my_module.py
CapWords MyClass
函数/方法 lower_with_under() my_function()
常量 CAPS_WITH_UNDER MAX_SIZE
变量 lower_with_under my_var
私有 _leading_underscore _private_var

避免:

  • 除了计数器/迭代器(ijk)之外的单字符名称
  • 任何名称中的破折号
  • __double_leading_and_trailing_underscore__(Python保留)

注释和文档字符串

文档字符串格式

对所有公共模块、函数、类和方法使用Google风格的文档字符串。

函数文档字符串:

def fetch_smalltable_rows(
    table_handle: smalltable.Table,
    keys: Sequence[bytes | str],
    require_all_keys: bool = False,
) -> Mapping[bytes, tuple[str, ...]]:
    """从Smalltable获取行。

    从由table_handle表示的Table实例中检索与给定键相关的行。
    字符串键将被UTF-8编码。

    参数:
        table_handle: 一个打开的smalltable.Table实例。
        keys: 表示要获取的表行的键的字符串序列。字符串键将被UTF-8编码。
        require_all_keys: 如果为True,如果任何键缺失则引发ValueError。

    返回:
        一个将键映射到相应的表行数据的字典。每一行都表示为字符串元组。

    引发:
        IOError: 访问smalltable时发生错误。
        ValueError: 一个键缺失且require_all_keys为True。
    """
    ...

类文档字符串:

class SampleClass:
    """这里总结类。

    更长的类信息...
    更长的类信息...

    属性:
        likes_spam: 一个布尔值,表示我们是否喜欢SPAM。
        eggs: 我们下蛋的整数计数。
    """

    def __init__(self, likes_spam: bool = False):
        """根据spam偏好初始化实例。

        参数:
            likes_spam: 定义实例是否表现出这种偏好。
        """
        self.likes_spam = likes_spam
        self.eggs = 0

块和内联注释

  • 使用完整的句子和正确的大写
  • 块注释与代码缩进到同一级别
  • 内联注释应至少由2个空格分隔
  • 谨慎使用内联注释
# 块注释解释以下代码。
# 可以跨越多行。
x = x + 1  # 内联注释(谨慎使用)

字符串

对于格式化,使用f-strings(Python 3.6+)。

正确:

x = f"name: {name}; score: {score}"

可接受:

x = "name: %s; score: %d" % (name, score)
x = "name: {}; score: {}".format(name, score)

错误:

x = "name: " + name + "; score: " + str(score)  # 避免+用于格式化

日志记录

使用%格式化进行日志记录,而不是f-strings(允许延迟评估):

logging.info("Request from %s resulted in %d", ip_address, status_code)

文件和资源

始终使用上下文管理器(with语句)进行文件操作:

with open("file.txt") as f:
    data = f.read()

语句

通常避免在一行上放置多个语句。

正确:

if foo:
    bar()

错误:

if foo: bar()  # 避免

主函数

对于可执行脚本,使用:

def main():
    ...

if __name__ == "__main__":
    main()

函数长度

保持函数专注且合理大小。如果一个函数超过大约40行,考虑拆分它,除非它仍然非常易读。

类型注释细节

向前声明

使用字符串引用进行向前引用:

class MyClass:
    def method(self) -> "MyClass":
        return self

类型别名

为复杂类型创建别名:

from typing import TypeAlias

ConnectionOptions: TypeAlias = dict[str, str]
Address: TypeAlias = tuple[str, int]
Server: TypeAlias = tuple[Address, ConnectionOptions]

TypeVars

为TypeVars使用描述性名称:

from typing import TypeVar

_T = TypeVar("_T")  # 好:私有的,无限制的
AddableType = TypeVar("AddableType", int, float, str)  # 好:描述性的

泛型

始终为泛型类型指定类型参数:

正确:

def get_names(employee_ids: list[int]) -> dict[int, str]:
    ...

错误:

def get_names(employee_ids: list) -> dict:  # 缺少类型参数
    ...

导入类型

直接导入typing符号:

from collections.abc import Mapping, Sequence
from typing import Any, Union

# 对于容器使用内置类型(Python 3.9+)
def foo(items: list[str]) -> dict[str, int]:
    ...

常见模式

属性

对于简单的属性访问,使用属性:

class Square:
    def __init__(self, side: float):
        self._side = side
    
    @property
    def area(self) -> float:
        return self._side ** 2

条件表达式

对于简单条件,使用三元运算符:

x = "yes" if condition else "no"

上下文管理器

在适当的时候创建自定义上下文管理器:

from contextlib import contextmanager

@contextmanager
def managed_resource(*args, **kwargs):
    resource = acquire_resource(*args, **kwargs)
    try:
        yield resource
    finally:
        release_resource(resource)

代码检查

对所有Python代码运行pylint。仅在必要时抑制警告,并提供清晰的解释:

dict = 'something'  # pylint: disable=redefined-builtin

总结

编写Python代码时:

  1. 为所有函数使用类型注释
  2. 一致地遵循命名约定
  3. 为所有公共API编写清晰的文档字符串
  4. 保持函数专注且合理大小
  5. 对于简单情况,使用推导式
  6. 在布尔上下文中更喜欢隐式假
  7. 对于格式化,使用f-strings
  8. 始终使用上下文管理器进行资源管理
  9. 运行pylint并修复问题
  10. 与现有代码保持一致性

额外资源

有关特定主题的详细参考,请参阅:

  • references/advanced_types.md - 包括Protocol、TypedDict、Literal、ParamSpec等高级类型注释模式
  • references/antipatterns.md - 常见的Python错误及其修复
  • references/docstring_examples.md - 所有Python构造的全面文档字符串示例