P

PEP 8 Python 代码风格指南

作者:鹿Sir开发工具v1

依据 PEP 8 与现代 Python 最佳实践规范编写、审查和重构 Python 代码,涵盖代码布局、命名约定、EAFP 哲学、类型提示、异常处理与基于 pytest 的测试驱动开发。当用户编写 .py 文件、进行 Python 代码审查、重构或关注 Python 代码质量时触发。触发词:Python 代码风格、PEP 8、代码审查、代码重构。

下载量
266
点赞
66
价格
免费

技能文档

---
name: majiayu000-python-pep8-style
title: PEP 8 Python 代码风格指南
category: 开发工具
description: 依据 PEP 8 与现代 Python 最佳实践规范编写、审查和重构 Python 代码,涵盖代码布局、命名约定、EAFP 哲学、类型提示、异常处理与基于 pytest 的测试驱动开发。当用户编写 .py 文件、进行 Python 代码审查、重构或关注 Python 代码质量时触发。触发词:Python 代码风格、PEP 8、代码审查、代码重构。
---

# PEP 8 Python 代码风格指南

本技能内置 PEP 8(Python 官方代码风格指南),并融合 Google Python 风格指南与社区通行标准中的现代 Python 最佳实践。

## 技能工作流

### 步骤1:判断使用场景

符合以下任一场景时应用本技能:

- 编写需要遵循 PEP 8 标准的新 Python 代码
- 审查 Python 代码的风格合规性
- 重构 Python 代码以提升可读性
- 学习地道的 Python 编程模式
- 搭建 Python 项目结构与工具链

### 步骤2:遵循核心设计哲学

**Python 之禅(PEP 20)**

```python
import this
# Beautiful is better than ugly.
# Explicit is better than implicit.
# Simple is better than complex.
# Complex is better than complicated.
# Flat is better than nested.
# Sparse is better than dense.
# Readability counts.
# Special cases aren't special enough to break the rules.
# Although practicality beats purity.
# Errors should never pass silently.
# Unless explicitly silenced.
# In the face of ambiguity, refuse the temptation to guess.
# There should be one-- and preferably only one --obvious way to do it.
# Now is better than never.
# Although never is often better than *right* now.
# If the implementation is hard to explain, it's a bad idea.
# If the implementation is easy to explain, it may be a good idea.
# Namespaces are one honking great idea -- let's do more of those!
```

**EAFP 优于 LBYL**:Python 偏好「请求宽恕比请求许可更容易」(EAFP),而非「三思而后行」(LBYL):

```python
# EAFP(Pythonic 风格)
try:
    value = data["key"]["nested"]
except KeyError:
    value = default_value

# LBYL(应避免)
if "key" in data and "nested" in data["key"]:
    value = data["key"]["nested"]
else:
    value = default_value
```

### 步骤3:遵守结构化限制

| 要素 | 限制 | 理由 |
|------|------|------|
| 行长度 | 79-88 字符 | PEP 8 规定 79,Black 规定 88 |
| 函数长度 | ≤25 行 | 单一职责 |
| 函数参数 | ≤5 个 | 更多时使用 dataclass/kwargs |
| 嵌套深度 | ≤4 层 | 抽取为独立函数 |
| import 分组 | 3 组 | 标准库 → 第三方 → 本地 |

### 步骤4:应用关键 PEP 8 规则

**代码布局**

```python
# 每级缩进 4 个空格(禁止用 Tab)
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# 二元运算符之前换行
income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction)

# 顶层定义前后空两行
class MyClass:
    pass


def my_function():
    pass
```

**导入(Imports)**

```python
# 标准库导入在最前
import os
import sys
from pathlib import Path

# 第三方导入其次(空行分隔)
import requests
from pydantic import BaseModel

# 本地导入最后(空行分隔)
from myapp.models import User
from myapp.utils import helpers

# 禁止通配符导入
# from module import *  # BAD
```

**命名约定**

| 类型 | 约定 | 示例 |
|------|------|------|
| 模块 | 小写下划线 | `my_module.py` |
| 包 | 小写 | `mypackage` |
| 类 | PascalCase | `MyClass` |
| 函数 | snake_case | `my_function()` |
| 变量 | snake_case | `my_variable` |
| 常量 | UPPER_SNAKE_CASE | `MAX_SIZE` |
| 私有成员 | 前置单下划线 | `_internal_var` |
| 类"私有"成员 | 前置双下划线 | `__mangled` |

**空白字符**

```python
# 正确 - 运算符两侧留空格
x = 1
y = x + 2
if x == 4:
    print(x, y)

# 正确 - 括号内不留空格
spam(ham[1], {eggs: 2})
foo = (0,)

# 正确 - 切片中冒号前不留空格
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3]

# 正确 - 关键字参数的 = 两侧不留空格
def complex(real, imag=0.0):
    return magic(r=real, i=imag)

# 正确 - 带类型注解时 = 两侧留空格
def munge(sep: str = None): ...
```

### 步骤5:使用现代 Python 特性

**类型提示(PEP 484、585)**

```python
from typing import Optional
from collections.abc import Sequence, Mapping

# 现代类型提示(Python 3.10+)
def process_items(
    items: list[str],
    config: dict[str, int] | None = None,
) -> dict[str, list[str]]:
    """Process items with optional configuration."""
    ...

# Protocol 用于鸭子类型
from typing import Protocol

class Serializable(Protocol):
    def to_dict(self) -> dict[str, Any]: ...
```

**数据类(Dataclasses)**

```python
from dataclasses import dataclass, field
from datetime import datetime

@dataclass
class User:
    username: str
    email: str
    created_at: datetime = field(default_factory=datetime.now)
    is_active: bool = True
    tags: list[str] = field(default_factory=list)

    def __post_init__(self) -> None:
        self.email = self.email.lower()
```

**上下文管理器**

```python
from contextlib import contextmanager

# 资源操作始终使用上下文管理器
with open("file.txt") as f:
    data = f.read()

# 自定义上下文管理器
@contextmanager
def database_transaction(connection):
    transaction = connection.begin()
    try:
        yield transaction
        transaction.commit()
    except Exception:
        transaction.rollback()
        raise
```

### 步骤6:按 TDD 流程开发(推荐)

**红阶段 - 先写失败的测试**

```python
import pytest

def test_user_creation_with_valid_email():
    user = User(email="test@example.com", name="Test")
    assert user.email == "test@example.com"

def test_user_creation_with_invalid_email_raises():
    with pytest.raises(ValueError, match="Invalid email"):
        User(email="invalid", name="Test")
```

**绿阶段 - 写最小实现让测试通过**

```python
@dataclass
class User:
    email: str
    name: str

    def __post_init__(self) -> None:
        if "@" not in self.email:
            raise ValueError("Invalid email format")
```

**重构阶段 - 在测试保护下改进**

```python
import re
from dataclasses import dataclass

EMAIL_PATTERN = re.compile(r"^[\w\.-]+@[\w\.-]+\.\w+$")

@dataclass
class User:
    email: str
    name: str

    def __post_init__(self) -> None:
        self._validate_email()
        self.email = self.email.lower()

    def _validate_email(self) -> None:
        if not EMAIL_PATTERN.match(self.email):
            raise ValueError(f"Invalid email format: {self.email}")
```

### 步骤7:规范异常处理

```python
# 定义具体异常
class UserNotFoundError(Exception):
    """Raised when a user cannot be found."""
    def __init__(self, user_id: int) -> None:
        self.user_id = user_id
        super().__init__(f"User {user_id} not found")

# 使用异常链
def get_user(user_id: int) -> User:
    try:
        return database.fetch_user(user_id)
    except DatabaseError as e:
        raise UserNotFoundError(user_id) from e

# 捕获具体异常
try:
    result = process_data(data)
except ValueError as e:
    logger.warning("Invalid data: %s", e)
    result = default_value
except (IOError, OSError) as e:
    logger.error("IO error: %s", e)
    raise ProcessingError("Failed to process") from e
```

### 步骤8:交付前质量自查

**代码风格**

- [ ] 符合 PEP 8(运行 `ruff check`)
- [ ] 行长 ≤88 字符(Black 标准)
- [ ] 导入分组有序(标准库 → 第三方 → 本地)
- [ ] 无通配符导入
- [ ] 命名约定一致

**类型安全**

- [ ] 所有公开函数有类型提示
- [ ] `mypy` 检查通过
- [ ] 可空类型使用 `Optional`
- [ ] 标注了返回类型

**测试**

- [ ] 先写测试(TDD)
- [ ] `pytest` 测试通过
- [ ] 覆盖边界情况
- [ ] 测试了异常场景

**文档**

- [ ] 公开 API 有 docstring(PEP 257)
- [ ] 模块级 docstring
- [ ] 复杂逻辑有说明

**现代 Python**

- [ ] 数据容器使用 dataclass
- [ ] 资源使用上下文管理器
- [ ] 采用 EAFP 模式
- [ ] 使用 f-string 格式化

### 步骤9:运行质量工具链

```bash
# 现代 Python 工具链
uv pip install ruff mypy pytest pytest-cov bandit

# 运行质量检查
ruff check .              # 代码检查(替代 flake8、isort)
ruff format .             # 代码格式化(替代 black)
mypy .                    # 类型检查
pytest --cov=src          # 测试并统计覆盖率
bandit -r src/            # 安全分析
```

使用说明

# PEP 8 Python 代码风格指南

依据 PEP 8 与现代 Python 最佳实践编写、审查和重构 Python 代码,让代码风格统一、可读性更高。

## 使用

安装本技能后,在对话中直接提出需求即可,例如:

```
帮我审查这段 Python 代码是否符合 PEP 8
用 pytest 按 TDD 流程实现一个邮箱校验类
```

## 工作原理

技能内置 PEP 8 规则手册与工作流:先判断使用场景(编写/审查/重构),再依次应用结构化限制、命名约定、空白规则、类型提示与异常处理规范,最后按质量清单自查并运行 ruff、mypy、pytest 等工具链完成交付。

如何安装此技能?

访问技能市场,点击「安装」按钮,按提示将技能包放入 AI 编程助手的 skills 目录即可。

浏览技能市场

支持平台:Qoder · QoderWork · Claude · Codex 等 AI 编程助手

PEP 8 Python 代码风格指南 - 免费 | 技能派