python-style-guide

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Python Style Guide

Python 风格指南

Comprehensive guidelines for writing clean, maintainable Python code based on Google's Python Style Guide.
本指南基于Google Python Style Guide编写,为编写清晰、可维护的Python代码提供全面规范。

Core Philosophy

核心理念

BE CONSISTENT. Match the style of the code around you. Use these guidelines as defaults, but always prioritize consistency with existing code.
保持一致性。优先适配周边已有代码的风格,本指南作为默认规范使用,但现有代码的一致性优先级更高。

Language Rules

语言规则

Imports

导入(Imports)

Use
import
statements for packages and modules in application code to avoid circular dependencies. For standard library and third-party packages, importing classes is acceptable.
Yes:
python
from pydantic import BaseModel  # Third-party: Class import OK
from pathlib import Path        # Stdlib: Class import OK
import sound_effects.utils      # App: Module import
from myproject import config    # App: Module import
No:
python
from myproject.utils import heavy_function  # App: Avoid direct function import if circular dep risk
应用代码中使用
import
语句导入包和模块,避免循环依赖。标准库和第三方包允许直接导入类。
✅ 正确示例:
python
from pydantic import BaseModel  # 第三方库:允许导入类
from pathlib import Path        # 标准库:允许导入类
import sound_effects.utils      # 应用代码:导入模块
from myproject import config    # 应用代码:导入模块
❌ 错误示例:
python
from myproject.utils import heavy_function  # 应用代码:如果存在循环依赖风险,避免直接导入函数

Import Formatting

导入格式规范

  • Group imports: standard library, third-party, application-specific
  • Alphabetize within each group
  • Use absolute imports (not relative imports)
  • One import per line (except for multiple items from
    typing
    or
    collections.abc
    )
python
undefined
  • 导入分组:标准库、第三方库、应用内代码,三组顺序排列
  • 每组内按字母顺序排序
  • 使用绝对导入(禁止相对导入)
  • 每行仅写一个导入语句(
    typing
    collections.abc
    的多个导入例外)
python
undefined

Standard library

标准库

import os import sys
import os import sys

Third-party

第三方库

import numpy as np import tensorflow as tf
import numpy as np import tensorflow as tf

Application-specific

应用内代码

from myproject.backend import api_utils
undefined
from myproject.backend import api_utils
undefined

Exceptions

异常(Exceptions)

Use exceptions appropriately. Do not suppress errors with bare
except:
clauses.
Yes:
python
try:
    result = risky_operation()
except ValueError as e:
    logging.error(f"Invalid value: {e}")
    raise
No:
python
try:
    result = risky_operation()
except:  # Too broad, hides bugs
    pass
合理使用异常,禁止使用空
except:
子句掩盖错误。
✅ 正确示例:
python
try:
    result = risky_operation()
except ValueError as e:
    logging.error(f"Invalid value: {e}")
    raise
❌ 错误示例:
python
try:
    result = risky_operation()
except:  # 捕获范围过宽,会隐藏bug
    pass

Type Annotations

类型注解(Type Annotations)

Annotate all function signatures. Type annotations improve code readability and catch errors early.
General rules:
  • Annotate all public APIs
  • Use built-in types (
    list
    ,
    dict
    ,
    set
    ) instead of
    typing.List
    , etc. (Python 3.9+)
  • Import typing symbols directly:
    from typing import Any, Union
  • Use
    None
    instead of
    type(None)
    or
    NoneType
python
def fetch_data(url: str, timeout: int = 30) -> dict[str, Any]:
    """Fetch data from URL."""
    ...

def process_items(items: list[str]) -> None:
    """Process a list of items."""
    ...
所有函数签名都需要添加类型注解,类型注解可以提升代码可读性,提前发现错误。
通用规则:
  • 所有公共API必须添加注解
  • Python 3.9+使用内置类型(
    list
    dict
    set
    )替代
    typing.List
  • 直接导入typing相关符号:
    from typing import Any, Union
  • 使用
    None
    替代
    type(None)
    NoneType
python
def fetch_data(url: str, timeout: int = 30) -> dict[str, Any]:
    """Fetch data from URL."""
    ...

def process_items(items: list[str]) -> None:
    """Process a list of items."""
    ...

Default Argument Values

默认参数值

Never use mutable objects as default values in function definitions.
Yes:
python
def foo(a: int, b: list[int] | None = None) -> None:
    if b is None:
        b = []
No:
python
def foo(a: int, b: list[int] = []) -> None:  # Mutable default - WRONG!
    b.append(a)
禁止在函数定义中使用可变对象作为默认值。
✅ 正确示例:
python
def foo(a: int, b: list[int] | None = None) -> None:
    if b is None:
        b = []
❌ 错误示例:
python
def foo(a: int, b: list[int] = []) -> None:  # 可变默认值,存在严重问题!
    b.append(a)

True/False Evaluations

布尔值判断

Use implicit false where possible. Empty sequences,
None
, and
0
are false in boolean contexts.
Yes:
python
if not users:  # Preferred
if not some_dict:
if value:
No:
python
if len(users) == 0:  # Verbose
if users == []:
if value == True:  # Never compare to True/False explicitly
尽可能使用隐式假值判断,空序列、
None
0
在布尔上下文中均为假值。
✅ 正确示例:
python
if not users:  # 推荐写法
if not some_dict:
if value:
❌ 错误示例:
python
if len(users) == 0:  # 写法冗余
if users == []:
if value == True:  # 禁止显式和True/False比较

Comprehensions & Generators

推导式与生成器

Use comprehensions and generators for simple cases. Keep them readable.
Yes:
python
result = [x for x in data if x > 0]
squares = (x**2 for x in range(10))
No:
python
undefined
简单场景使用推导式和生成器,注意保持可读性。
✅ 正确示例:
python
result = [x for x in data if x > 0]
squares = (x**2 for x in range(10))
❌ 错误示例:
python
undefined

Too complex

逻辑过于复杂,推荐使用普通循环替代

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 ] # Use a regular loop instead
undefined
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 ]
undefined

Lambda Functions

Lambda 函数

Use lambdas for one-liners only. For anything complex, define a proper function.
Yes:
python
sorted(data, key=lambda x: x.timestamp)
Acceptable but prefer named function:
python
def get_timestamp(item):
    return item.timestamp

sorted(data, key=get_timestamp)
仅单行逻辑可以使用lambda,复杂逻辑请定义正式命名函数。
✅ 正确示例:
python
sorted(data, key=lambda x: x.timestamp)
可接受但更推荐命名函数的写法:
python
def get_timestamp(item):
    return item.timestamp

sorted(data, key=get_timestamp)

Style Rules

风格规则

Line Length

行长度

Maximum line length: 88 characters. Exceptions allowed for imports, URLs, and long strings that can't be broken.
最大行长度为88个字符,导入语句、URL、无法拆分的长字符串可不受此限制。

Indentation

缩进

Use 4 spaces per indentation level. Never use tabs.
For hanging indents, align wrapped elements vertically or use 4-space hanging indent:
python
undefined
每个缩进层级使用4个空格,禁止使用制表符。
悬挂缩进可垂直对齐包裹元素,或使用4空格悬挂缩进:
python
undefined

Aligned with opening delimiter

与起始分隔符对齐

foo = long_function_name(var_one, var_two, var_three, var_four)
foo = long_function_name(var_one, var_two, var_three, var_four)

Hanging indent (4 spaces)

4空格悬挂缩进

foo = long_function_name( var_one, var_two, var_three, var_four)
undefined
foo = long_function_name( var_one, var_two, var_three, var_four)
undefined

Blank Lines

空行规范

  • Two blank lines between top-level definitions
  • One blank line between method definitions
  • Use blank lines sparingly within functions to show logical sections
  • 顶级定义之间空2行
  • 方法定义之间空1行
  • 函数内部可少量使用空行分隔逻辑块,避免过度使用

Naming Conventions

命名约定

TypeConventionExamples
Packages/Modules
lower_with_under
my_module.py
Classes
CapWords
MyClass
Functions/Methods
lower_with_under()
my_function()
Constants
CAPS_WITH_UNDER
MAX_SIZE
Variables
lower_with_under
my_var
Private
_leading_underscore
_private_var
Avoid:
  • Single character names except for counters/iterators (
    i
    ,
    j
    ,
    k
    )
  • Dashes in any name
  • __double_leading_and_trailing_underscore__
    (reserved for Python)
类型规范示例
包/模块
小写加下划线
my_module.py
大驼峰
MyClass
函数/方法
小写加下划线()
my_function()
常量
全大写下划线分隔
MAX_SIZE
变量
小写加下划线
my_var
私有成员
单下划线开头
_private_var
禁止用法:
  • 除计数器/迭代器(
    i
    j
    k
    )外禁止使用单字符命名
  • 任何命名中禁止使用横杠
  • 禁止使用
    __前后双下划线__
    格式(Python保留命名格式)

Comments and Docstrings

注释与文档字符串

Docstring Format

文档字符串格式

Use Google-style docstrings for all public modules, functions, classes, and methods.
Function docstring:
python
def fetch_smalltable_rows(
    table_handle: smalltable.Table,
    keys: Sequence[bytes | str],
    require_all_keys: bool = False,
) -> Mapping[bytes, tuple[str, ...]]:
    """Fetches rows from a Smalltable.

    Retrieves rows pertaining to the given keys from the Table instance
    represented by table_handle. String keys will be UTF-8 encoded.

    Args:
        table_handle: An open smalltable.Table instance.
        keys: A sequence of strings representing the key of each table
            row to fetch. String keys will be UTF-8 encoded.
        require_all_keys: If True, raise ValueError if any key is missing.

    Returns:
        A dict mapping keys to the corresponding table row data
        fetched. Each row is represented as a tuple of strings.

    Raises:
        IOError: An error occurred accessing the smalltable.
        ValueError: A key is missing and require_all_keys is True.
    """
    ...
Class docstring:
python
class SampleClass:
    """Summary of class here.

    Longer class information...
    Longer class information...

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam: bool = False):
        """Initializes the instance based on spam preference.

        Args:
            likes_spam: Defines if instance exhibits this preference.
        """
        self.likes_spam = likes_spam
        self.eggs = 0
所有公共模块、函数、类、方法都使用Google风格文档字符串。
函数文档字符串示例:
python
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实例中检索指定keys对应的行数据,字符串类型的key会被UTF-8编码。

    Args:
        table_handle: 已打开的smalltable.Table实例。
        keys: 要获取的表行key序列,字符串类型的key会被UTF-8编码。
        require_all_keys: 若为True,缺失任意key时抛出ValueError。

    Returns:
        字典类型,key对应获取到的表行数据,每行数据用字符串元组表示。

    Raises:
        IOError: 访问smalltable时发生错误。
        ValueError: require_all_keys为True时存在缺失的key。
    """
    ...
类文档字符串示例:
python
class SampleClass:
    """类的摘要说明。

    类的详细说明...
    类的详细说明...

    Attributes:
        likes_spam: 布尔值,表示是否喜欢SPAM。
        eggs: 整数,已产出的鸡蛋数量。
    """

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

        Args:
            likes_spam: 定义实例是否存在该偏好。
        """
        self.likes_spam = likes_spam
        self.eggs = 0

Block and Inline Comments

块注释与行内注释

  • Use complete sentences with proper capitalization
  • Block comments indent to the same level as the code
  • Inline comments should be separated by at least 2 spaces
  • Use inline comments sparingly
python
undefined
  • 使用完整句子,首字母大写
  • 块注释缩进与对应代码层级一致
  • 行内注释与代码之间至少间隔2个空格
  • 尽量减少行内注释的使用
python
undefined

Block comment explaining the following code.

块注释,用于说明下方代码

Can span multiple lines.

可跨行编写

x = x + 1 # Inline comment (use sparingly)
undefined
x = x + 1 # 行内注释(尽量少用)
undefined

Strings

字符串

Use f-strings for formatting (Python 3.6+).
Yes:
python
x = f"name: {name}; score: {score}"
Acceptable:
python
x = "name: %s; score: %d" % (name, score)
x = "name: {}; score: {}".format(name, score)
No:
python
x = "name: " + name + "; score: " + str(score)  # Avoid + for formatting
Python 3.6+使用f-string进行格式化。
✅ 正确示例:
python
x = f"name: {name}; score: {score}"
可接受写法:
python
x = "name: %s; score: %d" % (name, score)
x = "name: {}; score: {}".format(name, score)
❌ 错误示例:
python
x = "name: " + name + "; score: " + str(score)  # 禁止使用+拼接做格式化

Logging

日志规范

Use Loguru for logging with brace-style lazy formatting:
python
logger.info("Request from {} resulted in {}", ip_address, status_code)
Avoid standard
logging
with
%
formatting.
使用Loguru进行日志记录,采用大括号风格惰性格式化:
python
logger.info("Request from {} resulted in {}", ip_address, status_code)
禁止使用标准
logging
库的
%
格式化方式。

Files and Resources

文件与资源

For simple text operations, prefer
pathlib
methods:
python
data = Path("file.txt").read_text()
Path("output.txt").write_text("content")
For complex operations or non-text files, use context managers:
python
with open("image.png", "rb") as f:
    data = f.read()
简单文本操作优先使用
pathlib
方法:
python
data = Path("file.txt").read_text()
Path("output.txt").write_text("content")
复杂操作或非文本文件使用上下文管理器:
python
with open("image.png", "rb") as f:
    data = f.read()

Statements

语句规范

Generally avoid multiple statements on one line.
Yes:
python
if foo:
    bar()
No:
python
if foo: bar()  # Avoid
避免在一行内写多条语句。
✅ 正确示例:
python
if foo:
    bar()
❌ 错误示例:
python
if foo: bar()  # 禁止

Main

主函数规范

For executable scripts, use:
python
def main():
    ...

if __name__ == "__main__":
    main()
可执行脚本使用如下结构:
python
def main():
    ...

if __name__ == "__main__":
    main()

Function Length

函数长度

Keep functions focused and reasonably sized. If a function exceeds about 40 lines, consider splitting it unless it remains very readable.
保持函数职责单一、长度合理。如果函数超过40行,除非可读性极佳,否则建议拆分。

Type Annotation Details

类型注解详情

Forward Declarations

前向声明

Use string quotes for forward references:
python
class MyClass:
    def method(self) -> "MyClass":
        return self
前向引用使用字符串引号包裹:
python
class MyClass:
    def method(self) -> "MyClass":
        return self

Type Aliases

类型别名

Create aliases for complex types:
python
from typing import TypeAlias

ConnectionOptions: TypeAlias = dict[str, str]
Address: TypeAlias = tuple[str, int]
Server: TypeAlias = tuple[Address, ConnectionOptions]
为复杂类型创建别名:
python
from typing import TypeAlias

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

TypeVars

TypeVar

Use descriptive names for TypeVars:
python
from typing import TypeVar

_T = TypeVar("_T")  # Good: private, unconstrained
AddableType = TypeVar("AddableType", int, float, str)  # Good: descriptive
TypeVar使用描述性命名:
python
from typing import TypeVar

_T = TypeVar("_T")  # 推荐:私有、无约束
AddableType = TypeVar("AddableType", int, float, str)  # 推荐:命名清晰

Generics

泛型

Always specify type parameters for generic types:
Yes:
python
def get_names(employee_ids: list[int]) -> dict[int, str]:
    ...
No:
python
def get_names(employee_ids: list) -> dict:  # Missing type parameters
    ...
泛型类型必须指定类型参数:
✅ 正确示例:
python
def get_names(employee_ids: list[int]) -> dict[int, str]:
    ...
❌ 错误示例:
python
def get_names(employee_ids: list) -> dict:  # 缺失类型参数
    ...

Imports for Typing

类型相关导入

Import typing symbols directly:
python
from collections.abc import Mapping, Sequence
from typing import Any, Union
直接导入typing相关符号:
python
from collections.abc import Mapping, Sequence
from typing import Any, Union

Use built-in types for containers (Python 3.9+)

Python 3.9+容器使用内置类型

def foo(items: list[str]) -> dict[str, int]: ...
undefined
def foo(items: list[str]) -> dict[str, int]: ...
undefined

Modern Python Features

现代Python特性

Match Statements (Python 3.10+)

Match 语句(Python 3.10+)

Use structural pattern matching for complex conditionals:
python
def handle_response(response: dict) -> str:
    match response:
        case {"status": "ok", "data": data}:
            return f"Success: {data}"
        case {"status": "error", "message": msg}:
            return f"Error: {msg}"
        case {"status": status}:
            return f"Unknown status: {status}"
        case _:
            return "Invalid response"
Pattern matching with types:
python
def process(value: int | str | list) -> str:
    match value:
        case int(n) if n > 0:
            return f"Positive int: {n}"
        case int(n):
            return f"Non-positive int: {n}"
        case str(s):
            return f"String: {s}"
        case [first, *rest]:
            return f"List starting with {first}"
复杂条件判断使用结构模式匹配:
python
def handle_response(response: dict) -> str:
    match response:
        case {"status": "ok", "data": data}:
            return f"Success: {data}"
        case {"status": "error", "message": msg}:
            return f"Error: {msg}"
        case {"status": status}:
            return f"Unknown status: {status}"
        case _:
            return "Invalid response"
带类型的模式匹配:
python
def process(value: int | str | list) -> str:
    match value:
        case int(n) if n > 0:
            return f"Positive int: {n}"
        case int(n):
            return f"Non-positive int: {n}"
        case str(s):
            return f"String: {s}"
        case [first, *rest]:
            return f"List starting with {first}"

Dataclasses with Slots (Python 3.10+)

带Slots的Dataclass(Python 3.10+)

Use
slots=True
for memory efficiency and faster attribute access:
python
from dataclasses import dataclass

@dataclass(slots=True)
class Point:
    x: float
    y: float

@dataclass(slots=True, frozen=True)
class ImmutableConfig:
    host: str
    port: int
    timeout: float = 30.0
使用
slots=True
提升内存效率,加快属性访问速度:
python
from dataclasses import dataclass

@dataclass(slots=True)
class Point:
    x: float
    y: float

@dataclass(slots=True, frozen=True)
class ImmutableConfig:
    host: str
    port: int
    timeout: float = 30.0

Postponed Annotation Evaluation

延后注解求值

Use
from __future__ import annotations
for:
  • Forward references without quotes
  • Faster module import (annotations not evaluated at definition time)
python
from __future__ import annotations

class Node:
    def __init__(self, children: list[Node]) -> None:  # No quotes needed
        self.children = children

    def add_child(self, child: Node) -> None:
        self.children.append(child)
使用
from __future__ import annotations
可实现:
  • 无需引号即可使用前向引用
  • 模块导入速度更快(注解不会在定义时求值)
python
from __future__ import annotations

class Node:
    def __init__(self, children: list[Node]) -> None:  # 无需引号
        self.children = children

    def add_child(self, child: Node) -> None:
        self.children.append(child)

Exception Groups (Python 3.11+)

异常组(Python 3.11+)

Handle multiple exceptions simultaneously:
python
try:
    async with asyncio.TaskGroup() as tg:
        tg.create_task(task1())
        tg.create_task(task2())
except* ValueError as eg:
    for exc in eg.exceptions:
        logger.error("ValueError: {}", exc)
except* TypeError as eg:
    for exc in eg.exceptions:
        logger.error("TypeError: {}", exc)
同时处理多个异常:
python
try:
    async with asyncio.TaskGroup() as tg:
        tg.create_task(task1())
        tg.create_task(task2())
except* ValueError as eg:
    for exc in eg.exceptions:
        logger.error("ValueError: {}", exc)
except* TypeError as eg:
    for exc in eg.exceptions:
        logger.error("TypeError: {}", exc)

Common Patterns

常用模式

Properties

属性(Properties)

Use properties for simple attribute access:
python
class Square:
    def __init__(self, side: float):
        self._side = side
    
    @property
    def area(self) -> float:
        return self._side ** 2
简单属性访问使用property:
python
class Square:
    def __init__(self, side: float):
        self._side = side
    
    @property
    def area(self) -> float:
        return self._side ** 2

Conditional Expressions

条件表达式

Use ternary operators for simple conditions:
python
x = "yes" if condition else "no"
简单条件使用三元运算符:
python
x = "yes" if condition else "no"

Context Managers

上下文管理器

Create custom context managers when appropriate:
python
from contextlib import contextmanager

@contextmanager
def managed_resource(*args, **kwargs):
    resource = acquire_resource(*args, **kwargs)
    try:
        yield resource
    finally:
        release_resource(resource)
合适场景下创建自定义上下文管理器:
python
from contextlib import contextmanager

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

Linting

代码检查(Linting)

Run
ruff
on all Python code. Suppress warnings only when necessary:
python
dict = 'something'  # noqa: A001
所有Python代码都要运行
ruff
检查,仅必要时抑制警告:
python
dict = 'something'  # noqa: A001

Package
__init__.py
Files

__init__.py
文件规范

THERE MUST BE NO CODE IN
__init__.py
FILES.
Keep them empty.
python
undefined
__init__.py
文件中绝对不能包含代码
,保持文件为空。
python
undefined

init.py

init.py

This file should be empty

本文件应保持为空


Import from modules directly:
```python

直接从模块导入所需内容:
```python

Instead of: from mypackage import MyClass

不推荐:from mypackage import MyClass

Use: from mypackage.core import MyClass

推荐:from mypackage.core import MyClass

undefined
undefined

Preferred Libraries

推荐库

Use these libraries when applicable:
PurposeLibrary
Data validation/models
pydantic
Logging
loguru
CLI
cyclopts
,
rich
Testing
pytest
,
pytest-mock
对应场景优先使用以下库:
用途
数据校验/模型
pydantic
日志
loguru
CLI
cyclopts
,
rich
测试
pytest
,
pytest-mock

Summary

总结

When writing Python code:
  1. Use type annotations for all functions
  2. Follow naming conventions consistently
  3. Write clear docstrings for all public APIs
  4. Keep functions focused and reasonably sized
  5. Use comprehensions for simple cases
  6. Prefer implicit false in boolean contexts
  7. Use f-strings for formatting
  8. Always use context managers for resources
  9. Run
    ruff check
    and
    ruff format
  10. Keep
    __init__.py
    files empty
  11. BE CONSISTENT with existing code
编写Python代码时遵循以下规则:
  1. 所有函数添加类型注解
  2. 严格遵循命名约定
  3. 所有公共API编写清晰的文档字符串
  4. 保持函数职责单一、长度合理
  5. 简单场景使用推导式
  6. 布尔判断优先使用隐式假值
  7. 使用f-string做字符串格式化
  8. 资源操作始终使用上下文管理器
  9. 运行
    ruff check
    ruff format
  10. 保持
    __init__.py
    文件为空
  11. 与现有代码保持一致性

Additional Resources

额外资源

For detailed reference on specific topics, see:
  • references/advanced_types.md - Advanced type annotation patterns including Protocol, TypedDict, Literal, ParamSpec, and more
  • references/antipatterns.md - Common Python mistakes and their fixes
  • references/docstring_examples.md - Comprehensive docstring examples for all Python constructs
特定主题的详细参考可查看:
  • references/advanced_types.md - 高级类型注解模式,包括Protocol、TypedDict、Literal、ParamSpec等
  • references/antipatterns.md - Python常见错误及修复方案
  • references/docstring_examples.md - 所有Python结构的完整文档字符串示例