python从入门到精通-14附录

0 阅读34分钟

附录


附录 A: Python 与 Java/Kotlin 关键词对照表

以下对照表覆盖 Python 3.12+ 全部关键词(35 个)以及 Java/Kotlin 中语义最接近的对应概念。标注 [K] 表示 Kotlin 特有,[J] 表示 Java 特有,无标注表示两者通用。

A.1 定义与声明

PythonJava/Kotlin说明
classclass类定义,Python 无访问修饰符
deffun / 方法声明函数定义,Python 函数是一等公民
lambdalambda [K]匿名函数,Python lambda 只能单表达式
global无直接对应在函数内声明全局变量引用,Java/Kotlin 不需要
nonlocal无直接对应在嵌套函数内声明外层变量引用
yieldyield [K] / yield return [J]挂起函数并产出值,Python 中创建生成器
async defsuspend fun [K]定义协程函数
awaitawait [K] / .await() [J]等待协程完成
type (3.12+)无直接对应类型别名语句 type Point = tuple[float, float]
dataclassdata class [K] / record [J]自动生成 __init__/__repr__/__eq__

关键差异: Python 的 def 定义函数,不区分方法和函数——方法只是以 self 为第一参数的函数。Java/Kotlin 中方法是类的成员,有明确的归属。

# Python: 函数和方法用同一个 def
def standalone_func(x):        # 普通函数
    return x + 1

class Foo:
    def method(self, x):       # 方法 = 带 self 参数的函数
        return x + 1
// Kotlin: 函数和方法有不同声明位置
fun standaloneFunc(x: Int): Int = x + 1    // 顶层函数

class Foo {
    fun method(x: Int): Int = x + 1         // 成员方法
}

A.2 控制流

PythonJava/Kotlin说明
if / elif / elseif / else if / elsePython 用 elif,Java/Kotlin 用 else if
forforPython for 是迭代器遍历,Java 增强 for 类似
whilewhile / do-while [J]Python 没有 do-while
match / case [3.10+]when [K] / switch [J]结构化模式匹配
breakbreak跳出循环
continuecontinue跳过本次迭代
pass无直接对应空操作占位符,Java/Kotlin 用空块 {}
for ... else无直接对应循环正常结束时执行 else 块
while ... else无直接对应同上

关键差异: Python 的 for 只能遍历可迭代对象,没有传统 C 风格的 for (int i=0; i<n; i++)。需要索引时用 enumerate()range()

# Python: for-else 语法(Java/Kotlin 中没有)
for item in items:
    if item == target:
        break
else:
    # 循环正常结束(没有被 break)时执行
    print("未找到目标项")

A.3 逻辑与成员运算符

PythonJavaKotlin说明
and&&&&逻辑与,短路求值
or||||逻辑或,短路求值
not!!逻辑非
is==(引用)===身份比较(同一对象),不是值比较
is not!=(引用)!==身份不等
==.equals()==相等比较
in.contains()in成员检测
not in!.contains()!in非成员检测
:=(海象运算符)[3.8+]无直接对应无直接对应表达式内赋值

关键差异: Python 中 == 比较值,is 比较身份(内存地址)。Java 中 == 比较引用(基本类型除外),需要 .equals() 比较值。Kotlin 中 == 调用 .equals()=== 比较引用。这是最容易搞混的地方。

# Python
a = [1, 2, 3]
b = [1, 2, 3]
a == b       # True   — 值相等
a is b       # False  — 不同对象
a is not b   # True

# Java
Integer a = new Integer(42);
Integer b = new Integer(42);
a == b       // false  — 引用不同
a.equals(b)  // true   — 值相等

# Kotlin
val a = listOf(1, 2, 3)
val b = listOf(1, 2, 3)
a == b       // true   — 调用 equals()
a === b      // false  — 引用不同

A.4 面向对象

PythonJava/Kotlin说明
classclass类定义
selfthis实例引用,Python 必须显式声明为第一参数
__init__构造函数实例初始化,不是真正的构造函数(__new__ 才是)
__new__构造函数真正的构造方法,通常不需要重写
super()super调用父类方法,Python 3 可无参调用
__slots__无直接对应限制实例属性,节省内存
@propertyval / getter [K] / getter [J]属性访问器
@staticmethod伴生对象方法 [K] / static 方法 [J]静态方法
@classmethod伴生对象方法 [K] / static 工厂方法 [J]类方法,第一参数是类本身
__mro__无直接对应方法解析顺序(C3 线性化)
__getattr__无直接对应属性访问拦截(描述符协议)
__repr__toString()开发者友好表示
__str__toString()用户友好表示
__eq__equals()值相等比较
__hash__hashCode()哈希值
__call__operator fun invoke() [K]使实例可调用
@dataclassdata class [K] / record [J]值对象
@abstractmethodabstract抽象方法
__all__public / internal模块公开 API 声明

关键差异: Python 没有 public/private/protected 访问修饰符。约定上,单下划线 _name 表示"内部使用",双下划线 __name 触发名称改写(name mangling)。

# Python: 访问控制靠约定
class User:
    def __init__(self):
        self.name = "Alice"       # 公开属性
        self._email = "a@b.com"   # 约定内部使用(不强制)
        self.__secret = "pwd"     # 名称改写为 _User__secret

u = User()
u.name          # "Alice" — 正常访问
u._email        # "a@b.com" — 可以访问,但约定不要
u.__secret      # AttributeError! 实际存储为 _User__secret
u._User__secret # "pwd" — 改写后仍可访问(不是真正的私有)

A.5 异常处理

PythonJava/Kotlin说明
try / except / finallytry / catch / finally异常捕获
raisethrow抛出异常
assertassert [J] / check() [K]断言,Python 可全局禁用(-O
Exception 基类Exception / Throwable所有异常基类
except Exception as ecatch (Exception e)捕获并绑定异常对象
raise ... from ethrow new ... (cause) [J] / throw ... (e) [K]异常链
else(try 块)无直接对应try 块无异常时执行

关键差异: Python 中所有异常都是 unchecked,不需要声明 throws。Java 的 checked exception 是 Python 开发者最不习惯的概念之一。

# Python: 异常链
try:
    int("abc")
except ValueError as e:
    raise RuntimeError("解析失败") from e
    # 输出: RuntimeError: 解析失败
    #       The above exception was the direct cause of...
// Java: 异常链
try {
    Integer.parseInt("abc");
} catch (NumberFormatException e) {
    throw new RuntimeException("解析失败", e);
}

A.6 模块与包

PythonJava/Kotlin说明
import moduleimport package.Class导入模块/包
from module import nameimport package.Class导入特定名称
import module as aliasimport package.Class as Alias [K]别名导入
__name__无直接对应模块名,"__main__" 表示入口
__all__public / @Api声明模块公开 API
__file__无直接对应模块文件路径
__path__无直接对应包搜索路径
__init__.pypackage-info.java包初始化文件
sys.pathclasspath模块搜索路径

关键差异: Python 的包是通过目录 + __init__.py 实现的,不是 Java 的命名空间目录结构。Python 的 import 是运行时语句,不是编译时声明。

A.7 类型与内省

PythonJava/Kotlin说明
type(obj)obj.getClass() / obj::class获取对象类型
isinstance(obj, Cls)obj instanceof Cls / obj is Cls类型检查
issubclass(A, B)A.isAssignableFrom(B)继承关系检查
hasattr(obj, name)反射 API属性存在检查
getattr(obj, name)反射 API动态获取属性
setattr(obj, name, val)反射 API动态设置属性
callable(obj)obj is Function可调用检查
dir(obj)反射 API列出所有属性和方法
vars(obj)反射 API返回 __dict__
: int(类型注解): Int类型声明(Python 不强制)

A.8 上下文管理与其他

PythonJava/Kotlin说明
withuse [K] / try-with-resources [J]上下文管理器(资源自动释放)
as无直接对应上下文管理器别名 / 导入别名
del无直接对应删除变量/属性/列表元素(引用计数减一)
yieldyield [K] / yield return [J]生成器
yield from无直接对应委托生成器
async / awaitsuspend / await [K]异步编程
True / False / Nonetrue / false / null布尔与空值
NotImplemented无直接对应比较运算符应返回的特殊单例
Ellipsis (...)无直接对应省略号,用于切片和类型提示占位

A.9 Python 全部关键词速查(35 个)

False      await      else       import     pass
None       break      except     in         raise
True       class      finally    is         return
and        continue   for        lambda     try
as         def        from       nonlocal   while
assert     del        global     not        with
async      elif       if         or         yield
match [3.10+]   case [3.10+]   type [3.12+]

Java 有 50 个关键词 + 2 个保留字(goto, const)。Kotlin 有约 80 个关键词(含 soft keywords)。Python 的关键词数量最少,体现了其"极简"设计哲学。


附录 B: 常用库生态映射(Java/Kotlin → Python)

按功能领域分类,每个映射给出 Python 侧的推荐首选备选方案,以及选择理由。

B.1 Web 框架

Java/KotlinPython 首选Python 备选说明
Spring BootFastAPIDjango, FlaskFastAPI 原生异步 + 自动 OpenAPI 文档,最接近 Spring Boot 的开发体验
KtorFastAPIStarlette, LitestarKtor 的协程模型与 FastAPI 的 async/await 天然对应
JAX-RS / JerseyFlaskFastAPI轻量 REST 框架
MicronautLitestarFastAPI编译时依赖注入(Litestar 用装饰器实现)

选型建议: 从 Spring Boot 迁移 → FastAPI。需要完整 CMS/后台管理 → Django。需要极简 → Flask。

B.2 ORM 与数据库

Java/KotlinPython 首选Python 备选说明
HibernateSQLAlchemy 2.0Tortoise ORMSQLAlchemy 2.0 的 Session 模式类似 Hibernate EntityManager
ExposedSQLAlchemy 2.0PeeweeExposed 的 DSL 风格与 SQLAlchemy Core 类似
jOOQSQLModelSQLAlchemy Core类型安全的 SQL 构建器
MyBatisSQLAlchemy Coreraw SQL + asyncpg直接写 SQL 的场景
JPA CriteriaSQLAlchemy 2.0 select()`类型安全的查询构建
# SQLAlchemy 2.0 风格(类似 Hibernate Criteria)
from sqlalchemy import select

stmt = select(User).where(User.age > 18).order_by(User.name)
result = session.execute(stmt).scalars().all()

B.3 HTTP 客户端

Java/KotlinPython 首选Python 备选说明
OkHttphttpxrequestshttpx 同时支持同步和异步
Retrofithttpxrespx (mock)httpx + Pydantic 可实现类似 Retrofit 的类型安全调用
Ktor Clienthttpxaiohttp协程模型一致
Apache HttpClienthttpxurllib3urllib3 是 requests/httpx 的底层传输层
Feignopenapi-python-client从 OpenAPI spec 自动生成客户端
# httpx: 同时支持同步和异步
import httpx

# 同步
response = httpx.get("https://api.example.com/users")
data = response.json()

# 异步
async with httpx.AsyncClient() as client:
    response = await client.get("https://api.example.com/users")
    data = response.json()

B.4 JSON 序列化

Java/KotlinPython 首选Python 备选说明
Jacksonorjsonujson, msgspecorjson 是最快的 JSON 库,支持 datetime/UUID 等
Gsonorjsonjson (stdlib)简单场景用 stdlib json 即可
kotlinx.serializationpydanticmsgspec, attrsPydantic 提供类型验证 + 序列化,最接近 Kotlin 的类型安全序列化
Moshimsgspecorjsonmsgspec 支持从 JSON schema 生成 Struct 类型
import orjson

# 序列化(自动处理 datetime、UUID、dataclass)
data = {"time": datetime.now(), "id": uuid.uuid4()}
json_bytes = orjson.dumps(data)       # 返回 bytes,比 json.dumps 快 3-5x
parsed = orjson.loads(json_bytes)     # 自动还原 datetime

B.5 日志

Java/KotlinPython 首选Python 备选说明
SLF4J + Logbacklogurustructlog, stdlib loggingloguru 零配置、彩色输出、自动 rotation,最接近 Logback 开箱即用的体验
Log4j2structloglogurustructlog 适合结构化日志(JSON 格式),适合生产环境
kotlin-logginglogurustdlib logging简单场景
from loguru import logger

# 零配置使用,自动彩色输出到 stderr
logger.info("用户登录", user_id=42, ip="192.168.1.1")
logger.error("请求失败", status_code=500, url="/api/users")

# 添加文件输出(自动 rotation)
logger.add("app.log", rotation="500 MB", retention="30 days", level="INFO")

B.6 测试

Java/KotlinPython 首选Python 备选说明
JUnit 5pytestunittest (stdlib)pytest 是 Python 测试的事实标准,fixture 机制远超 JUnit
MockK / Mockitopytest + unittest.mockrespx (HTTP mock)pytest-mock 提供更简洁的 mock API
AssertJ / Truthpytest + assertpyhamcrest链式断言
Testcontainerstestcontainers-pythondocker-compose容器化集成测试
JaCoCocoveragepytest-cov代码覆盖率
Property-based Testinghypothesis类似 QuickCheck / jqwik
ArchUnit无成熟替代Python 生态缺少架构测试工具
# pytest: fixture 依赖注入(类似 JUnit 5 @ExtendWith)
import pytest

@pytest.fixture
def db_session():
    session = create_session()
    yield session
    session.close()

def test_user_creation(db_session):
    user = User(name="Alice")
    db_session.add(user)
    assert db_session.query(User).count() == 1

B.7 构建与依赖管理

Java/KotlinPython 首选Python 备选说明
MavenuvPoetry, hatchuv 速度极快(Rust 实现),类似 Gradle 的体验
Gradle (Kotlin DSL)uvPDM, flituv 的 pyproject.toml 类似 build.gradle.kts
Gradle Wrapperuvpipxuv 自带 Python 版本管理
BOM (Bill of Materials)uv 的 resolutionuv 自动解析依赖版本
Maven CentralPyPIPython 包仓库

B.8 配置管理

Java/KotlinPython 首选Python 备选说明
application.ymlpydantic-settingsdynaconfPydantic Settings 提供类型安全的配置 + 环境变量支持
HOCONdynaconfpydantic-settingsdynaconf 支持 YAML/TOML/ENV/.env 多种来源
@Value / @ConfigurationPropertiespydantic-settingsBaseSettings 类似 @ConfigurationProperties
Spring Profilespydantic-settings + envdynaconf通过环境变量切换配置
from pydantic_settings import BaseSettings

class AppConfig(BaseSettings):
    database_url: str = "sqlite:///dev.db"
    debug: bool = False
    max_connections: int = 10

    model_config = {"env_prefix": "APP_"}

config = AppConfig()
# APP_DATABASE_URL=postgresql://... python app.py

B.9 任务调度与异步

Java/KotlinPython 首选Python 备选说明
QuartzAPSchedulerCeleryAPScheduler 类似 Quartz 的轻量调度
kotlinx.coroutinesasynciotrioPython 原生协程支持
Spring @AsyncCeleryarq, dramatiq分布式任务队列
ScheduledExecutorServiceasyncio.create_taskloopy协程任务
Project Loom (虚拟线程)asyncio + free-threaded [3.13]Python 3.13 实验性自由线程

B.10 消息队列

Java/KotlinPython 首选Python 备选说明
Kafkakafka-python-ngaiokafka, confluent-kafkakafka-python-ng 是活跃维护的 fork
RabbitMQaio-pikapikaaio-pika 原生异步
Redis Streamsredis-pyredis-py 原生支持 Streams
AWS SQSboto3aiobotocoreAWS 官方 SDK
JMSconfluent-kafkaPython 没有统一的 JMS 抽象

B.11 数据验证

Java/KotlinPython 首选Python 备选说明
Bean Validation (Hibernate Validator)pydanticmarshmallow, attrsPydantic V2 性能接近 Rust 实现
@NotNull / @Size / @EmailField(..., min_length=1) / EmailStrPydantic 用类型注解声明约束
Jakarta Validationpydantic同上
from pydantic import BaseModel, EmailStr, Field

class UserCreate(BaseModel):
    name: str = Field(min_length=1, max_length=100)
    email: EmailStr
    age: int = Field(ge=0, le=150)

user = UserCreate(name="Alice", email="alice@example.com", age=30)
# 验证失败时抛出 ValidationError,包含所有错误详情

B.12 API 文档

Java/KotlinPython 首选Python 备选说明
Swagger / SpringfoxFastAPI 自动生成FastAPI 从类型注解自动生成 OpenAPI 文档
Spring REST DocsFastAPI 自动生成无需额外配置
OpenAPI Generatordatamodel-code-generator从 OpenAPI spec 生成 Pydantic 模型

B.13 CLI 框架

Java/KotlinPython 首选Python 备选说明
picoclityperclicktyper 基于 Typer(类型提示),最接近 picocli 的注解驱动体验
JCommanderclickargparse (stdlib)click 更成熟
Spring Shellclickrich-clickrich-click 提供彩色输出
import typer

app = typer.Typer()

@app.command()
def hello(name: str, count: int = 1):
    """向用户问好"""
    for _ in range(count):
        typer.echo(f"Hello, {name}!")

if __name__ == "__main__":
    app()
# python cli.py hello --name Alice --count 3

B.14 数据处理与工具

Java/KotlinPython 首选Python 备选说明
Apache Commons Langmore-itertoolstoolzitertools 的高级封装
Apache Commons IOpathlib (stdlib)shutil (stdlib)pathlib 提供面向对象的路径操作
Guavatoolzmore-itertools函数式工具集
Stream APIitertools + 列表推导式toolzPython 没有专门的 Stream 类,但推导式更简洁
Vavrreturnsresult函数式 Either/Maybe/Result 类型

B.15 日期时间

Java/KotlinPython 首选Python 备选说明
java.time (JSR 310)datetime + zoneinfo (stdlib)pendulumPython 3.9+ 的 zoneinfo 类似 java.time.ZoneId
ThreeTenBPpendulumarrowpendulum API 最接近 Java 的 LocalDate/LocalDateTime
Joda-TimependulumJoda-Time 已被 java.time 取代
from datetime import datetime, timezone
from zoneinfo import ZoneInfo

# 类似 Java 的 ZonedDateTime
now = datetime.now(ZoneInfo("Asia/Shanghai"))
# 类似 Java 的 Instant
instant = datetime.now(timezone.utc)

B.16 模板引擎

Java/KotlinPython 首选Python 备选说明
ThymeleafJinja2MakoJinja2 是 Python 模板的事实标准
FreeMarkerJinja2Jinja2 语法更简洁
PebbleJinja2Pebble 本身就受 Jinja2 启发

B.17 缓存

Java/KotlinPython 首选Python 备选说明
Caffeinecachetoolsfunctools.lru_cache (stdlib)cachetools 的 TTLCache 类似 Caffeine
Spring Cachecachetools装饰器方式缓存
Redis (Spring Data Redis)redis-py官方 Redis 客户端
Ehcachediskcache支持磁盘持久化的缓存

B.18 数据库迁移

Java/KotlinPython 首选Python 备选说明
FlywayAlembicSQLAlchemy 配套迁移工具,类似 Flyway 的版本化迁移
LiquibaseAlembicyoyo-migrationsAlembic 更轻量
Prisma MigrateAlembicPython 生态以 Alembic 为主

B.19 其他常用工具

功能Java/KotlinPython 首选说明
环境变量System.getenv()python-dotenv + os.environ.env 文件加载
密码哈希Spring Security BCryptpasslib多算法支持
JWTjjwt / java-jwtPyJWTJSON Web Token
HTTP 基础认证Spring SecurityFastAPI + HTTPBasic内置支持
CORSSpring @CrossOriginFastAPI CORSMiddleware中间件方式
WebSocketSpring WebSocketFastAPI WebSocket原生支持
依赖注入Spring DI / Koindependency-injectorPython DI 不是主流范式
AOPSpring AOP无成熟替代Python 用装饰器实现类似功能
CSV 处理OpenCSVpandas / csv (stdlib)pandas 适合大数据量
Excel 处理Apache POIopenpyxlxlsx 读写
PDF 生成iTextreportlab / WeasyPrintreportlab 更底层
邮件JavaMailaiosmtplib异步 SMTP 客户端
定时任务@ScheduledAPScheduler轻量级调度

附录 C: PEP 8 编码规范精要 vs Java/Kotlin 编码规范

PEP 8 是 Python 社区的编码风格指南,类似于 Java 的 Google Java Style Guide 或 Kotlin Coding Conventions。以下对比两者的关键差异。

C.1 命名规范

元素Python (PEP 8)JavaKotlin
变量/函数/方法snake_casecamelCasecamelCase
类/类型PascalCasePascalCasePascalCase
常量UPPER_SNAKE_CASEUPPER_SNAKE_CASEUPPER_SNAKE_CASE / object
模块/包snake_case小写小写
私有成员_leading_underscoreprivateprivate / _
受保护成员_single_underscoreprotectedprotected
名称改写(伪私有)__double_underscore
魔术方法__dunder__operator
接口无接口概念,用 ProtocolPascalCase (I前缀可选)PascalCase
类型参数PascalCaseT, E, K, VT, TValue
# Python 命名示例
MAX_RETRIES = 3                          # 常量
class UserRepository:                     # 类
    def find_by_id(self, user_id: int):   # 方法
        pass

    def _internal_helper(self):           # 私有(约定)
        pass

    def __name_mangle(self):              # 伪私有(名称改写)
        pass
// Kotlin 命名示例
const val MAX_RETRIES = 3                 // 常量
class UserRepository {                     // 类
    fun findById(userId: Int): User? {    // 方法
        return null
    }

    private fun internalHelper() {        // 私有
    }
}

C.2 缩进与格式

规则Python (PEP 8)JavaKotlin
缩进4 空格(强制)4 空格(约定)4 空格(约定)
Tab vs 空格只用空格(Python 3 禁止混用)任意(IDE 处理)任意(IDE 处理)
行长度79 字符(代码),72(文档字符串)120(Google)/ 100(很多团队)120
续行括号隐式续行,或反斜杠同 Python同 Python
空行 — 顶层定义2 个空行1 个空行1 个空行
空行 — 类内方法1 个空行1 个空行1 个空行
文件编码UTF-8(默认)UTF-8UTF-8

C.3 空格使用

# === Python 空格规则 ===

# 推荐: 运算符两侧各一个空格
x = 1 + 2
y = x * 3 + 4

# 推荐: 逗号后面一个空格,前面无空格
items = [1, 2, 3]
func(a, b, c)

# 推荐: 函数定义默认参数无空格
def func(key=value):
    pass

# 推荐: 冒号后一个空格(切片除外)
if x == 1:
    pass
dct = {1: 2, 3: 4}

# 推荐: 括号内侧无空格
spam(ham[1], {eggs: 2})
foo = (1,)

# 不推荐: 多余空格
x=1                # 赋值运算符两侧缺空格
func (1)           # 函数名和括号之间有空格
dct = { 1: 2 }     # 括号内侧有多余空格
my_list[ 1 ]       # 索引括号内侧有空格

C.4 导入排序

# === PEP 8 导入顺序 ===
# 1. 标准库
import os
import sys
from pathlib import Path
from typing import Optional

# 2. 第三方库
import httpx
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

# 3. 本地模块
from app.models import User
from app.services import UserService

# 规则:
# - 每组之间空一行
# - 每组内按字母排序
# - 避免通配符导入 from module import *
# - 使用 isort 或 ruff format 自动排序
// Java 导入顺序(Google Style)
// 1. 所有导入放在 package 声明之后
// 2. 按以下顺序分组,每组内按 ASCII 排序:
//    a. 所有静态导入
//    b. com.* 导入
//    c. 其他导入(javax.*, org.*, net.*, 等)
//    d. java.* 导入
import static java.util.stream.Collectors.toList;

import com.google.common.base.Strings;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

C.5 文档字符串 vs Javadoc / KDoc

# === Python: docstring(三引号字符串) ===
def calculate_area(radius: float) -> float:
    """计算圆的面积。

    Args:
        radius: 圆的半径,必须为正数。

    Returns:
        圆的面积。

    Raises:
        ValueError: 当半径为负数时。

    Examples:
        >>> calculate_area(5.0)
        78.53981633974483
    """
    import math
    return math.pi * radius ** 2


class UserRepository:
    """用户数据访问层。

    负责用户实体的 CRUD 操作和查询。
    """

    def find_by_id(self, user_id: int) -> User | None:
        """根据 ID 查找用户。

        Args:
            user_id: 用户唯一标识。

        Returns:
            用户实体,不存在时返回 None。
        """
        ...
// === Kotlin: KDoc ===
/**
 * 计算圆的面积。
 *
 * @param radius 圆的半径,必须为正数。
 * @return 圆的面积。
 * @throws IllegalArgumentException 当半径为负数时。
 */
fun calculateArea(radius: Double): Double {
    require(radius >= 0) { "半径不能为负数" }
    return Math.PI * radius * radius
}

关键差异:

  • Python 用三引号字符串 """...""",放在函数/类体内部第一行
  • Java/Kotlin 用 /** ... */,放在声明之前
  • Python docstring 是运行时可访问的(func.__doc__),Javadoc/KDoc 是编译时处理的
  • Python 推荐 Google 风格或 NumPy 风格,Java/KDoc 用 @param/@return/@throws

C.6 类型注解

# Python: 类型注解(可选,运行时不强制)
from typing import Optional

def greet(name: str, times: int = 1) -> list[str]:
    """向用户问好。"""
    return [f"Hello, {name}!" for _ in range(times)]

# Python 3.10+ 新语法
def process(data: int | None = None) -> list[dict[str, int]]:
    ...

# Java: 类型声明(强制,编译时检查)
// public List<String> greet(String name, int times) { ... }

C.7 使用 Ruff 自动格式化

# pyproject.toml 中的 Ruff 配置
[tool.ruff]
line-length = 88                    # Black 默认 88(比 PEP 8 的 79 宽)
target-version = "py312"

[tool.ruff.lint]
select = [
    "E",    # pycodestyle errors
    "W",    # pycodestyle warnings
    "F",    # pyflakes
    "I",    # isort(导入排序)
    "N",    # pep8-naming
    "UP",   # pyupgrade
    "B",    # flake8-bugbear
    "SIM",  # flake8-simplify
]
ignore = ["E501"]  # 行长度由 formatter 处理

[tool.ruff.format]
quote-style = "double"
indent-style = "space"

附录 D: Java/Kotlin 开发者 Top 20 常见 Python 陷阱

每个陷阱都来自 JVM 开发者的真实踩坑经历,配有错误示例和正确示例。

陷阱 1: 可变默认参数

Java/Kotlin 思维: 方法参数的默认值每次调用都是新的。

Python 现实: 默认参数在函数定义时求值一次,所有调用共享同一个对象。

# ❌ 错误:所有调用共享同一个列表
def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item("a"))  # ['a']
print(add_item("b"))  # ['a', 'b']  ← 不是 ['b']!
print(add_item("c"))  # ['a', 'b', 'c']  ← 越来越多!
# ✅ 正确:用 None 作为默认值
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item("a"))  # ['a']
print(add_item("b"))  # ['b']

根因: Python 的 def 是执行语句,默认参数在定义时求值并绑定到函数对象。Java/Kotlin 的方法默认参数在每次调用时求值。


陷阱 2: 类属性 vs 实例属性

Java/Kotlin 思维: 类的字段就是实例字段。

Python 现实: 在 class 块中直接赋值的是类属性,所有实例共享。

# ❌ 错误:count 是类属性,所有实例共享
class Dog:
    count = 0  # 类属性!

    def __init__(self, name):
        self.name = name
        self.count += 1  # 读取类属性,在实例上创建新属性

a = Dog("Rex")
b = Dog("Buddy")
print(a.count)  # 0  ← 没变!因为 += 在实例上创建了新属性
print(Dog.count)  # 0
print(b.count)  # 0
# ✅ 正确:在 __init__ 中初始化实例属性
class Dog:
    def __init__(self, name):
        self.name = name
        self.count = 0  # 实例属性

# 如果确实需要类级别的计数器
class Dog:
    _count = 0  # 类属性

    def __init__(self, name):
        self.name = name
        Dog._count += 1  # 通过类名修改类属性

    @classmethod
    def get_count(cls):
        return cls._count

陷阱 3: is vs ==

Java/Kotlin 思维: == 比较引用,.equals() 比较值。

Python 现实: == 比较值,is 比较身份(引用)。与 Java 正好相反。

# ❌ 错误:用 is 比较值
a = [1, 2, 3]
b = [1, 2, 3]
print(a is b)   # False — 不同对象
print(a == b)   # True  — 值相等

# 特别注意:小整数缓存
x = 256
y = 256
print(x is y)   # True  — CPython 缓存了 -5 到 256

x = 257
y = 257
print(x is y)   # False — 超出缓存范围!
# ✅ 正确:比较值用 ==,比较身份用 is
# 值比较
assert a == b

# 身份比较(通常只用于 None 和单例)
value = some_function()
if value is None:
    ...
if value is not None:
    ...

陷阱 4: 整除 // vs 真除 /

Java/Kotlin 思维: 整数除法自动截断(5 / 2 = 2)。

Python 现实: / 始终返回浮点数,// 才是整除。

# ❌ Java 开发者直觉错误
result = 5 / 2
print(result)    # 2.5  ← 不是 2!
print(type(result))  # <class 'float'>

# ❌ 以为 / 对整数返回整数
items = [1, 2, 3, 4, 5]
mid = len(items) / 2
# items[mid]  # TypeError: list indices must be integers, not float
# ✅ 正确
5 / 2     # 2.5   — 真除法(总是 float)
5 // 2    # 2     — 整除(floor division)
-5 // 2   # -3    — 向下取整(不是截断!)
int(5 / 2)  # 2   — 截断(类似 Java)

# 列表索引用 //
mid = len(items) // 2
items[mid]  # 正确

特别注意: Python 的 //向下取整(floor),不是 Java 的向零截断(truncate)。-5 // 2 = -3(Python)vs -5 / 2 = -2(Java)。


陷阱 5: for 循环变量泄漏

Java/Kotlin 思维: 循环变量作用域限于循环体内。

Python 现实: for 循环变量在循环结束后仍然存在。

# ❌ 循环变量泄漏到外部作用域
for i in range(5):
    pass

print(i)  # 4 — i 仍然存在!
# ✅ 正确:不需要 i 时用 _
for _ in range(5):
    do_something()

# 如果后续需要用到循环结果,用列表推导式
results = [process(x) for x in range(5)]

Python 3.x 中列表推导式有自己的作用域,不会泄漏。但 for 循环会。


陷阱 6: 闭包延迟绑定

Java/Kotlin 思维: lambda 捕获变量的值。

Python 现实: 闭包捕获的是变量的引用,不是值。循环中的闭包共享同一个变量。

# ❌ 错误:所有函数都返回最后一个值
funcs = []
for i in range(3):
    funcs.append(lambda: i)

print([f() for f in funcs])  # [2, 2, 2]  ← 全是 2!
# ✅ 正确方案 1:用默认参数绑定当前值
funcs = []
for i in range(3):
    funcs.append(lambda i=i: i)  # 默认参数在定义时求值

print([f() for f in funcs])  # [0, 1, 2]

# ✅ 正确方案 2:用列表推导式(有自己的作用域)
funcs = [lambda i=i: i for i in range(3)]
print([f() for f in funcs])  # [0, 1, 2]

根因: Python 的闭包是后期绑定(late binding),变量在函数被调用时查找,不是在定义时。Java 的匿名类/lambda 捕获的是 effectively final 变量的值。


陷阱 7: 浅拷贝 vs 深拷贝

Java/Kotlin 思维: clone()copy() 通常做深拷贝(取决于实现)。

Python 现实: list.copy() / dict.copy() / copy.copy() 都是浅拷贝

# ❌ 浅拷贝:内层对象仍然共享
original = [[1, 2], [3, 4]]
shallow = original.copy()

shallow[0][0] = 99
print(original)  # [[99, 2], [3, 4]]  ← original 也被修改了!
# ✅ 深拷贝:完全独立
import copy

original = [[1, 2], [3, 4]]
deep = copy.deepcopy(original)

deep[0][0] = 99
print(original)  # [[1, 2], [3, 4]]  ← 不受影响
# ✅ 如果只需要一层拷贝,用列表推导式
shallow = [row[:] for row in original]

陷阱 8: 字符串不可变

Java/Kotlin 思维: 字符串不可变(这点一致)。

Python 现实: 字符串确实不可变,但拼接方式的性能差异极大。

# ❌ 性能差:循环中用 + 拼接(每次创建新字符串)
result = ""
for s in many_strings:
    result += s  # O(n^2) — 每次创建新字符串并复制

# ❌ 以为 StringBuilder 有等价物
# ✅ 正确:用 join(O(n))
result = "".join(many_strings)

# ✅ 如果需要逐步构建,用 StringIO
from io import StringIO
buf = StringIO()
for s in many_strings:
    buf.write(s)
result = buf.getvalue()

Java 开发者对字符串不可变不陌生,但容易忽略 Python 中 str.join() 是拼接的唯一正确方式。


陷阱 9: import 循环依赖

Java/Kotlin 思维: 编译器检测循环依赖并报错。

Python 现实: Python 允许循环 import,但会导致 AttributeErrorImportError,且错误信息不直观。

# ❌ 循环依赖
# module_a.py
from module_b import B  # module_b 还没加载完,B 可能还不存在

class A:
    pass

# module_b.py
from module_a import A  # 同样的问题

class B:
    pass

# 运行 module_a 时: ImportError: cannot import name 'B' from 'module_b'
# ✅ 方案 1:在函数/方法内延迟导入
# module_a.py
class A:
    def method(self):
        from module_b import B  # 运行到这里时 module_b 已加载完
        return B()

# ✅ 方案 2:重构,提取公共模块
# common.py
class Base:
    pass

# module_a.py
from common import Base
class A(Base):
    pass

# module_b.py
from common import Base
class B(Base):
    pass

陷阱 10: GIL 与多线程

Java/Kotlin 思维: 多线程可以并行执行 CPU 密集型任务。

Python 现实: GIL(全局解释器锁)导致同一时刻只有一个线程执行 Python 字节码。多线程只能并行处理 I/O 密集型任务。

# ❌ 多线程对 CPU 密集型任务无效
import threading

def cpu_bound():
    total = sum(i * i for i in range(10_000_000))

threads = [threading.Thread(target=cpu_bound) for _ in range(4)]
for t in threads:
    t.start()
for t in threads:
    t.join()
# 不会比单线程快,甚至更慢(线程切换开销)
# ✅ CPU 密集型:用多进程
from multiprocessing import Pool

def cpu_bound(n):
    return sum(i * i for i in range(n))

with Pool(4) as pool:
    results = pool.map(cpu_bound, [10_000_000] * 4)

# ✅ I/O 密集型:多线程或 asyncio 都可以
import concurrent.futures
import httpx

urls = ["https://httpbin.org/get"] * 10

with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
    results = list(executor.map(lambda u: httpx.get(u).json(), urls))

Python 3.13 引入了实验性的 free-threaded 模式(PEP 703),可以禁用 GIL,但生态兼容性仍在完善中。


陷阱 11: 异常都是 unchecked

Java/Kotlin 思维: 编译器强制处理 checked exception(throws 声明)。

Python 现实: 所有异常都是 unchecked,调用者不会被告知可能抛出什么异常。

# ❌ 不知道函数可能抛出什么异常
def parse_config(path: str) -> dict:
    with open(path) as f:        # 可能抛 FileNotFoundError
        return json.load(f)       # 可能抛 json.JSONDecodeError

# 调用者不知道需要处理这些异常
config = parse_config("config.json")  # 没有任何提示
# ✅ 用文档字符串声明可能抛出的异常
def parse_config(path: str) -> dict:
    """解析配置文件。

    Args:
        path: 配置文件路径。

    Returns:
        配置字典。

    Raises:
        FileNotFoundError: 配置文件不存在。
        json.JSONDecodeError: 配置文件格式错误。
    """
    with open(path) as f:
        return json.load(f)

# ✅ 用类型注解 + Pydantic 避免异常
from pydantic import BaseModel

class Config(BaseModel):
    name: str
    port: int = 8080

config = Config.model_validate_json(content)  # 验证错误 → ValidationError

陷阱 12: 没有方法重载

Java/Kotlin 思维: 同名方法可以有不同参数类型(重载)。

Python 现实: 后定义的函数会覆盖先定义的。Python 用其他方式实现类似功能。

# ❌ 第二个定义覆盖了第一个
class Service:
    def process(self, data: str):
        return data.upper()

    def process(self, data: int):      # 覆盖了上面的方法!
        return data * 2

s = Service()
s.process("hello")  # TypeError: can't multiply sequence by non-int of type 'str'
# ✅ 方案 1:用 Union 类型 + isinstance 判断
from typing import Union

class Service:
    def process(self, data: Union[str, int]) -> Union[str, int]:
        if isinstance(data, str):
            return data.upper()
        return data * 2

# ✅ 方案 2:用 @singledispatch(单分派泛型函数)
from functools import singledispatch

@singledispatch
def process(data):
    raise NotImplementedError(f"不支持类型: {type(data)}")

@process.register(str)
def _(data: str):
    return data.upper()

@process.register(int)
def _(data: int):
    return data * 2

# ✅ 方案 3:用 @overload 做类型检查提示(运行时无效)
from typing import overload

class Service:
    @overload
    def process(self, data: str) -> str: ...

    @overload
    def process(self, data: int) -> int: ...

    def process(self, data):
        if isinstance(data, str):
            return data.upper()
        return data * 2

陷阱 13: boolint 的子类

Java/Kotlin 思维: boolean 是独立类型,不能和 int 互操作。

Python 现实: bool 继承自 intTrue == 1False == 0

# ❌ 意外的行为
print(True + True)         # 2
print(True * 10)           # 10
print(sum([True, False, True]))  # 2
print(isinstance(True, int))     # True

# ❌ 类型检查陷阱
def process(flag: bool):
    if flag:
        print("yes")

process(1)     # "yes" — 1 被当作 True
process(2)     # "yes" — 任何非零数都是 True
process("hi")  # "yes" — 非空字符串也是 True
# ✅ 如果需要严格布尔检查
def process(flag: bool):
    if flag is True or flag is False:
        print("严格布尔值")
    else:
        raise TypeError(f"期望 bool,得到 {type(flag)}")

# ✅ 类型注解 + 运行时检查
from pydantic import BaseModel, Field

class Config(BaseModel):
    debug: bool = Field(strict=True)  # 严格模式,不接受 1/0

Config(debug=True)   # OK
Config(debug=1)      # ValidationError

陷阱 14: None 的判断用 is

Java/Kotlin 思维: null 检查用 ==

Python 现实: None 是单例,必须用 is 判断。== None 虽然通常能工作,但不是惯用写法,且可以被重载。

# ❌ 不推荐
if value == None:
    ...

# ❌ 更糟:某些类型重载了 __eq__
class Tricky:
    def __eq__(self, other):
        return True  # 永远相等!

t = Tricky()
print(t == None)  # True ← 错误!
print(t is None)  # False ← 正确
# ✅ 正确:始终用 is / is not
if value is None:
    ...

if value is not None:
    ...

陷阱 15: 列表推导式变量作用域(Python 2 遗留问题)

背景: Python 2 中列表推导式的循环变量会泄漏到外部作用域。Python 3 已修复此问题。

# Python 2(已过时)
x = [i for i in range(5)]
print(i)  # 4 — 变量泄漏!

# Python 3(当前)
x = [i for i in range(5)]
print(i)  # NameError: name 'i' is not defined ← 已修复
# ✅ Python 3 中列表推导式有自己的作用域
# 但生成器表达式在函数参数中时要注意
# 以下代码在 Python 3 中是安全的
results = [f(x) for x in range(10)]

这个陷阱主要影响维护 Python 2 遗留代码的开发者。新项目不需要担心。


陷阱 16: *args / **kwargs 命名只是约定

Java/Kotlin 思维: varargs 是语言特性,名称固定。

Python 现实: *** 是解包运算符,argskwargs 只是参数名约定。

# ❌ 以为 args 和 kwargs 是关键字
def func(*args, **kwargs):
    pass

# ✅ 以下写法完全等价
def func(*variables, **options):
    pass

def func(*a, **kw):
    pass

# * 和 ** 才是语法,后面的名字随意
# 但强烈建议用 args 和 kwargs,这是社区约定
# ✅ 实际使用中的常见模式
def log(message: str, *args: object, **kwargs: object) -> None:
    """日志函数,接受任意位置参数和关键字参数。"""
    formatted = message.format(*args)
    print(formatted, kwargs)

log("用户 {} 登录,IP={}", "Alice", ip="192.168.1.1")
# 输出: 用户 Alice 登录,IP= {'ip': '192.168.1.1'}

陷阱 17: __init__ 不是构造函数

Java/Kotlin 思维: 构造函数创建并初始化对象。

Python 现实: __new__ 才是构造函数(创建对象),__init__ 是初始化方法(配置已创建的对象)。

# ❌ 以为 __init__ 控制对象创建
class Singleton:
    _instance = None

    def __init__(self):
        # 这个方法每次都会被调用!
        # 即使返回缓存实例,__init__ 也会再次执行
        pass
# ✅ 单例模式需要重写 __new__
class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self):
        # 注意:__init__ 仍然会被每次调用!
        # 需要额外防护
        if not hasattr(self, '_initialized'):
            self._initialized = True
            self.data = []

关键区别:

  • __new__(cls): 类方法,负责创建实例并返回。类似 Java 的 new 关键字 + 构造函数
  • __init__(self): 实例方法,负责初始化已创建的实例。类似 Java 构造函数体
  • 绝大多数情况下只需要重写 __init____new__ 只在单例、不可变类型子类化等特殊场景需要

陷阱 18: super() 在多继承中的行为

Java/Kotlin 思维: Java 只支持单继承,super 调用唯一父类。

Python 现实: Python 支持多继承,super() 遵循 MRO(方法解析顺序),不是简单的"调用父类"。

# ❌ 以为 super() 只调用直接父类
class A:
    def method(self):
        print("A")
        super().method()  # A 的 MRO 中的下一个

class B:
    def method(self):
        print("B")

class C(A, B):
    pass

C().method()
# 输出:
# A
# B    ← 不是报错!super() 沿 MRO 链继续
# ✅ 理解 MRO
print(C.__mro__)
# (<class 'C'>, <class 'A'>, <class 'B'>, <class 'object'>)

# ✅ 如果需要调用特定父类
class A:
    def method(self):
        print("A")

class B:
    def method(self):
        print("B")

class C(A, B):
    def method(self):
        A.method(self)  # 直接调用 A 的方法,不走 MRO
        B.method(self)  # 直接调用 B 的方法

C().method()
# 输出:
# A
# B

实践建议: 除非有明确的菱形继承需求,否则避免多继承。优先使用组合(composition)或混入类(mixin)。


陷阱 19: 生成器只能消费一次

Java/Kotlin 思维: Stream / Sequence 可以重复遍历。

Python 现实: 生成器(generator)是单向迭代器,消费完就空了。

# ❌ 生成器只能遍历一次
def numbers():
    yield 1
    yield 2
    yield 3

gen = numbers()
print(list(gen))  # [1, 2, 3]
print(list(gen))  # [] ← 空了!
# ✅ 方案 1:需要多次遍历时,转为列表
nums = list(numbers())
print(list(nums))  # [1, 2, 3]
print(list(nums))  # [1, 2, 3]

# ✅ 方案 2:每次创建新的生成器
print(list(numbers()))  # [1, 2, 3]
print(list(numbers()))  # [1, 2, 3]

# ✅ 方案 3:用 itertools.tee 复制迭代器
import itertools
gen = numbers()
a, b = itertools.tee(gen, 2)
print(list(a))  # [1, 2, 3]
print(list(b))  # [1, 2, 3]

注意: 以下类型也是一次性消费的:zip()map()filter()reversed()(对某些类型)、文件对象的行迭代。


陷阱 20: try/except 性能(异常路径慢)

Java/Kotlin 思维: 异常处理有性能开销,但不影响正常路径。

Python 现实: try 块的设置几乎零开销,但 except 块的执行非常慢。Python 鼓励 EAFP(Easier to Ask Forgiveness than Permission)风格。

# ✅ Python 推荐的 EAFP 风格(正常路径快)
try:
    value = dct["key"]
except KeyError:
    value = default

# ❌ Python 不推荐的 LBYL 风格(每次都要检查,正常路径反而慢)
if "key" in dct:
    value = dct["key"]
else:
    value = default
# ✅ 性能对比
import timeit

# EAFP: 快(try 块设置几乎零开销)
timeit.timeit('try: d["x"]\nexcept KeyError: pass',
              setup='d={"y": 1}', number=10_000_000)
# ~0.15 秒

# LBYL: 慢(每次都要执行 in 检查)
timeit.timeit('if "x" in d: d["x"]',
              setup='d={"y": 1}', number=10_000_000)
# ~0.25 秒

# 但如果异常频繁发生,EAFP 会更慢
# 经验法则:异常是罕见情况时用 EAFP,异常是常见情况时用 LBYL

总结: Python 的异常处理性能特征与 Java 相反。Java 中异常路径极慢(需要构建完整堆栈跟踪),Python 中异常路径也慢但 try 块设置几乎免费。因此 Python 推荐 EAFP,Java 推荐 LBYL。


附录 E: pyproject.toml 完整模板

pyproject.toml 基础配置详见 1.4 pyproject.toml,本附录提供可直接使用的完整模板。

以下提供三种主流工具的完整 pyproject.toml 模板。推荐使用 uv(速度最快、最现代)。

E.1 uv 模板(推荐)

# ============================================================
# pyproject.toml — uv 项目模板
# 适用于: uv 0.4+ / Python 3.12+
# ============================================================

[project]
name = "my-project"
version = "0.1.0"
description = "项目描述"
readme = "README.md"
license = { text = "MIT" }
requires-python = ">=3.12"
authors = [
    { name = "Your Name", email = "your@email.com" },
]
keywords = ["python", "web", "api"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Framework :: FastAPI",
    "Topic :: Internet :: WWW/HTTP",
]

# === 依赖 ===
dependencies = [
    "fastapi>=0.115.0",
    "uvicorn[standard]>=0.30.0",
    "pydantic>=2.9.0",
    "pydantic-settings>=2.5.0",
    "sqlalchemy>=2.0.35",
    "httpx>=0.27.0",
    "loguru>=0.7.0",
]

# === 开发依赖 ===
[dependency-groups]
dev = [
    # 测试
    "pytest>=8.3.0",
    "pytest-cov>=5.0.0",
    "pytest-asyncio>=0.24.0",
    "pytest-mock>=3.14.0",
    "httpx",              # TestClient 需要
    "hypothesis>=6.115.0",

    # 代码质量
    "ruff>=0.6.0",
    "mypy>=1.11.0",
    "pre-commit>=3.8.0",

    # 类型存根
    "types-python-dateutil>=2.9.0",
]

# === 构建系统 ===
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

# === Ruff 配置 ===
[tool.ruff]
target-version = "py312"
line-length = 88
src = ["src"]

[tool.ruff.lint]
select = [
    "E",     # pycodestyle errors
    "W",     # pycodestyle warnings
    "F",     # pyflakes
    "I",     # isort(导入排序)
    "N",     # pep8-naming
    "UP",    # pyupgrade(自动升级语法)
    "B",     # flake8-bugbear(常见 bug)
    "SIM",   # flake8-simplify(简化代码)
    "C4",    # flake8-comprehensions(推导式优化)
    "DTZ",   # flake8-datetimez(时区安全)
    "TCH",   # flake8-type-checking(类型导入优化)
    "RUF",   # ruff 特有规则
]
ignore = [
    "E501",  # 行长度由 formatter 处理
    "B008",  # 函数调用作为默认参数(FastAPI Depends 需要)
]

[tool.ruff.lint.isort]
known-first-party = ["my_project"]

[tool.ruff.lint.pyupgrade]
keep-runtime-typing = false  # Python 3.12+ 不需要 from __future__ import annotations

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
docstring-code-format = true

# === mypy 配置 ===
[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_any_generics = true
check_untyped_defs = true
no_implicit_optional = true

[[tool.mypy.overrides]]
module = [
    "uvicorn.*",
    "loguru.*",
]
ignore_missing_imports = true

# === pytest 配置 ===
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_functions = ["test_*"]
addopts = [
    "-v",
    "--tb=short",
    "--strict-markers",
]
markers = [
    "slow: 慢速测试",
    "integration: 集成测试",
    "unit: 单元测试",
]
asyncio_mode = "auto"

# === coverage 配置 ===
[tool.coverage.run]
source = ["src"]
branch = true
omit = [
    "tests/*",
    "*/__init__.py",
]

[tool.coverage.report]
show_missing = true
fail_under = 80
exclude_lines = [
    "pragma: no cover",
    "if TYPE_CHECKING:",
    "if __name__ == .__main__.:",
    "raise NotImplementedError",
    "@abstractmethod",
    "@overload",
]

E.2 Poetry 模板

# ============================================================
# pyproject.toml — Poetry 项目模板
# 适用于: Poetry 1.8+ / Python 3.12+
# ============================================================

[tool.poetry]
name = "my-project"
version = "0.1.0"
description = "项目描述"
authors = ["Your Name <your@email.com>"]
readme = "README.md"
license = "MIT"
requires-python = ">=3.12"

[tool.poetry.dependencies]
python = "^3.12"
fastapi = "^0.115.0"
uvicorn = { extras = ["standard"], version = "^0.30.0" }
pydantic = "^2.9.0"
pydantic-settings = "^2.5.0"
sqlalchemy = "^2.0.35"
httpx = "^0.27.0"
loguru = "^0.7.0"

[tool.poetry.group.dev.dependencies]
pytest = "^8.3.0"
pytest-cov = "^5.0.0"
pytest-asyncio = "^0.24.0"
pytest-mock = "^3.14.0"
hypothesis = "^6.115.0"
ruff = "^0.6.0"
mypy = "^1.11.0"
pre-commit = "^3.8.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

# Ruff、mypy、pytest、coverage 配置同 E.1
# 此处省略,直接复制 E.1 中对应的 [tool.*] 部分

E.3 Hatch 模板

# ============================================================
# pyproject.toml — Hatch 项目模板
# 适用于: Hatch 1.12+ / Python 3.12+
# ============================================================

[project]
name = "my-project"
version = "0.1.0"
description = "项目描述"
readme = "README.md"
license = "MIT"
requires-python = ">=3.12"
authors = [
    { name = "Your Name", email = "your@email.com" },
]
dependencies = [
    "fastapi>=0.115.0",
    "uvicorn[standard]>=0.30.0",
    "pydantic>=2.9.0",
    "pydantic-settings>=2.5.0",
    "sqlalchemy>=2.0.35",
    "httpx>=0.27.0",
    "loguru>=0.7.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.3.0",
    "pytest-cov>=5.0.0",
    "pytest-asyncio>=0.24.0",
    "hypothesis>=6.115.0",
    "ruff>=0.6.0",
    "mypy>=1.11.0",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.envs.default]
features = ["dev"]

[tool.hatch.envs.default.scripts]
test = "pytest {args}"
test-cov = "pytest --cov {args}"
lint = "ruff check . && ruff format --check ."
lint-fix = "ruff check --fix . && ruff format ."
typecheck = "mypy src"

[tool.hatch.envs.test]
features = ["dev"]

[tool.hatch.envs.test.scripts]
cov = "pytest --cov-report=term-missing --cov {args}"

# Ruff、mypy、pytest、coverage 配置同 E.1
# 此处省略,直接复制 E.1 中对应的 [tool.*] 部分

E.4 配置对比速查

特性uvPoetryHatch
安装速度极快(Rust)中等中等
锁文件uv.lockpoetry.lock无(依赖 pip)
依赖解析Rust 实现Python 实现pip
Python 版本管理内置需要 pyenv需要 pyenv
虚拟环境管理内置内置内置
脚本管理uv runpoetry runhatch run
发布uv publishpoetry publishhatch publish
插件系统丰富丰富
学习曲线
推荐场景新项目首选已有 Poetry 项目需要复杂构建矩阵

附录 F: 推荐学习资源与社区

F.1 官方文档(必读)

资源链接说明
Python 官方文档docs.python.org/3/最权威的参考,教程部分质量极高
Python Tutorialdocs.python.org/3/tutorial/官方教程,适合快速入门
Python Language Referencedocs.python.org/3/reference…语言规范,深入理解语法细节
Python Standard Librarydocs.python.org/3/library/标准库文档,itertools/functools/collections 必读
PEP 索引peps.python.org/Python 增强提案,理解设计决策的必读
typing 模块文档docs.python.org/3/library/t…类型系统完整参考
FastAPI 文档fastapi.tiangolo.com/FastAPI 官方文档,质量极高
SQLAlchemy 文档docs.sqlalchemy.org/SQLAlchemy 2.0 文档
Pydantic V2 文档docs.pydantic.dev/数据验证与序列化

F.2 书籍推荐

书名适合阶段说明
Fluent Python (2nd Edition)中高级Luciano Ramalho 著,深入理解 Python 数据模型、OOP、函数式编程。JVM 开发者必读
Python Cookbook (3rd Edition)中级David Beazley 著,实用编程技巧集
Effective Python (3rd Edition)中级Brett Slatkin 著,90 条具体建议,类似 Effective Java
CPython Internals高级Anthony Shaw 著,深入 CPython 实现原理
Architecture Patterns with Python高级Harry Percival & Bob Gregory 著,DDD/Clean Architecture 在 Python 中的实践
Robust Python中高级Patrick Viafore 著,类型驱动开发实践
FastAPI: Modern Python Web Development中级Bill Lubanovic 著,FastAPI 实战

F.3 在线课程

课程平台说明
Corey Schafer - Python TutorialsYouTube (免费)高质量视频教程,OOP/装饰器/生成器系列极佳
ArjanCodesYouTube (免费)Python 设计模式、Clean Code 实践
mCodingYouTube (免费)Python 底层原理、性能优化
Real Pythonrealpython.com/大量高质量教程和视频
Talk Python to MePodcast每周 Python 生态访谈

F.4 社区和论坛

社区链接说明
Python Discoursediscuss.python.org/官方讨论论坛,PEP 讨论在这里进行
r/Pythonreddit.com/r/PythonReddit Python 社区
r/learnpythonreddit.com/r/learnpyth…适合提问和学习
Stack Overflowstackoverflow.com/questions/t…技术问答
Python 中文社区www.python.org.cn/中文 Python 社区
Python Discorddiscord.gg/python实时讨论

F.5 工具和库

类别工具说明
包管理uv速度最快的包管理器(Rust 实现)
代码检查Ruff替代 flake8/pylint/isort/black 的全能工具(Rust 实现)
类型检查mypy静态类型检查
格式化Ruff format替代 Black(Ruff 内置)
测试pytest测试框架
交互式IPython增强的交互式解释器
NotebookJupyter交互式笔记本
调试debugpyVS Code Python 调试器后端
性能分析py-spy采样性能分析器(Rust 实现)
依赖可视化pipdeptree查看依赖树
环境管理uv / pyenvPython 版本管理

F.6 博客和新闻

资源链接说明
What's New in Pythondocs.python.org/3/whatsnew/每个版本的变更日志
Python Weeklywww.pythonweekly.com/每周 Python 新闻邮件
PyCoder's Weeklypycoders.com/每周 Python 文章和工具推荐
Talk Python Podcasttalkpython.fm/Python 播客
The Changelogchangelog.com/podcast开源技术播客(含 Python)
Ned Batchelder's Blognedbatchelder.com/blog/Python 核心开发者博客
Anthony Shaw's Blogblog.anthonyshaw.org/CPython 内部原理
Martin Heinz's Blogmartinheinz.dev/Python 工程实践

F.7 PEP 精选阅读清单

对于想深入理解 Python 设计哲学的开发者,以下 PEP 最值得阅读:

PEP标题为什么值得读
PEP 8Style Guide编码规范
PEP 20The Zen of PythonPython 设计哲学(import this
PEP 3107Function Annotations类型注解的起源
PEP 484Type Hints类型提示规范
PEP 572Assignment Expressions海象运算符 :=
PEP 634Structural Pattern Matchingmatch/case 语法
PEP 695Type Parameter SyntaxPython 3.12 泛型新语法
PEP 703Making the GIL Optional自由线程(no-GIL)
PEP 636Pattern Matching Tutorial模式匹配教程
PEP 484Type Hints类型提示完整规范

附录结束。回到 目录