附录
附录 A: Python 与 Java/Kotlin 关键词对照表
以下对照表覆盖 Python 3.12+ 全部关键词(35 个)以及 Java/Kotlin 中语义最接近的对应概念。标注
[K]表示 Kotlin 特有,[J]表示 Java 特有,无标注表示两者通用。
A.1 定义与声明
| Python | Java/Kotlin | 说明 |
|---|---|---|
class | class | 类定义,Python 无访问修饰符 |
def | fun / 方法声明 | 函数定义,Python 函数是一等公民 |
lambda | lambda [K] | 匿名函数,Python lambda 只能单表达式 |
global | 无直接对应 | 在函数内声明全局变量引用,Java/Kotlin 不需要 |
nonlocal | 无直接对应 | 在嵌套函数内声明外层变量引用 |
yield | yield [K] / yield return [J] | 挂起函数并产出值,Python 中创建生成器 |
async def | suspend fun [K] | 定义协程函数 |
await | await [K] / .await() [J] | 等待协程完成 |
type (3.12+) | 无直接对应 | 类型别名语句 type Point = tuple[float, float] |
dataclass | data 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 控制流
| Python | Java/Kotlin | 说明 |
|---|---|---|
if / elif / else | if / else if / else | Python 用 elif,Java/Kotlin 用 else if |
for | for | Python for 是迭代器遍历,Java 增强 for 类似 |
while | while / do-while [J] | Python 没有 do-while |
match / case [3.10+] | when [K] / switch [J] | 结构化模式匹配 |
break | break | 跳出循环 |
continue | continue | 跳过本次迭代 |
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 逻辑与成员运算符
| Python | Java | Kotlin | 说明 |
|---|---|---|---|
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 面向对象
| Python | Java/Kotlin | 说明 |
|---|---|---|
class | class | 类定义 |
self | this | 实例引用,Python 必须显式声明为第一参数 |
__init__ | 构造函数 | 实例初始化,不是真正的构造函数(__new__ 才是) |
__new__ | 构造函数 | 真正的构造方法,通常不需要重写 |
super() | super | 调用父类方法,Python 3 可无参调用 |
__slots__ | 无直接对应 | 限制实例属性,节省内存 |
@property | val / 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] | 使实例可调用 |
@dataclass | data class [K] / record [J] | 值对象 |
@abstractmethod | abstract | 抽象方法 |
__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 异常处理
| Python | Java/Kotlin | 说明 |
|---|---|---|
try / except / finally | try / catch / finally | 异常捕获 |
raise | throw | 抛出异常 |
assert | assert [J] / check() [K] | 断言,Python 可全局禁用(-O) |
Exception 基类 | Exception / Throwable | 所有异常基类 |
except Exception as e | catch (Exception e) | 捕获并绑定异常对象 |
raise ... from e | throw 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 模块与包
| Python | Java/Kotlin | 说明 |
|---|---|---|
import module | import package.Class | 导入模块/包 |
from module import name | import package.Class | 导入特定名称 |
import module as alias | import package.Class as Alias [K] | 别名导入 |
__name__ | 无直接对应 | 模块名,"__main__" 表示入口 |
__all__ | public / @Api | 声明模块公开 API |
__file__ | 无直接对应 | 模块文件路径 |
__path__ | 无直接对应 | 包搜索路径 |
__init__.py | package-info.java | 包初始化文件 |
sys.path | classpath | 模块搜索路径 |
关键差异: Python 的包是通过目录 + __init__.py 实现的,不是 Java 的命名空间目录结构。Python 的 import 是运行时语句,不是编译时声明。
A.7 类型与内省
| Python | Java/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 上下文管理与其他
| Python | Java/Kotlin | 说明 |
|---|---|---|
with | use [K] / try-with-resources [J] | 上下文管理器(资源自动释放) |
as | 无直接对应 | 上下文管理器别名 / 导入别名 |
del | 无直接对应 | 删除变量/属性/列表元素(引用计数减一) |
yield | yield [K] / yield return [J] | 生成器 |
yield from | 无直接对应 | 委托生成器 |
async / await | suspend / await [K] | 异步编程 |
True / False / None | true / 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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Spring Boot | FastAPI | Django, Flask | FastAPI 原生异步 + 自动 OpenAPI 文档,最接近 Spring Boot 的开发体验 |
| Ktor | FastAPI | Starlette, Litestar | Ktor 的协程模型与 FastAPI 的 async/await 天然对应 |
| JAX-RS / Jersey | Flask | FastAPI | 轻量 REST 框架 |
| Micronaut | Litestar | FastAPI | 编译时依赖注入(Litestar 用装饰器实现) |
选型建议: 从 Spring Boot 迁移 → FastAPI。需要完整 CMS/后台管理 → Django。需要极简 → Flask。
B.2 ORM 与数据库
| Java/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Hibernate | SQLAlchemy 2.0 | Tortoise ORM | SQLAlchemy 2.0 的 Session 模式类似 Hibernate EntityManager |
| Exposed | SQLAlchemy 2.0 | Peewee | Exposed 的 DSL 风格与 SQLAlchemy Core 类似 |
| jOOQ | SQLModel | SQLAlchemy Core | 类型安全的 SQL 构建器 |
| MyBatis | SQLAlchemy Core | raw SQL + asyncpg | 直接写 SQL 的场景 |
| JPA Criteria | SQLAlchemy 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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| OkHttp | httpx | requests | httpx 同时支持同步和异步 |
| Retrofit | httpx | respx (mock) | httpx + Pydantic 可实现类似 Retrofit 的类型安全调用 |
| Ktor Client | httpx | aiohttp | 协程模型一致 |
| Apache HttpClient | httpx | urllib3 | urllib3 是 requests/httpx 的底层传输层 |
| Feign | openapi-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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Jackson | orjson | ujson, msgspec | orjson 是最快的 JSON 库,支持 datetime/UUID 等 |
| Gson | orjson | json (stdlib) | 简单场景用 stdlib json 即可 |
| kotlinx.serialization | pydantic | msgspec, attrs | Pydantic 提供类型验证 + 序列化,最接近 Kotlin 的类型安全序列化 |
| Moshi | msgspec | orjson | msgspec 支持从 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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| SLF4J + Logback | loguru | structlog, stdlib logging | loguru 零配置、彩色输出、自动 rotation,最接近 Logback 开箱即用的体验 |
| Log4j2 | structlog | loguru | structlog 适合结构化日志(JSON 格式),适合生产环境 |
| kotlin-logging | loguru | stdlib 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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| JUnit 5 | pytest | unittest (stdlib) | pytest 是 Python 测试的事实标准,fixture 机制远超 JUnit |
| MockK / Mockito | pytest + unittest.mock | respx (HTTP mock) | pytest-mock 提供更简洁的 mock API |
| AssertJ / Truth | pytest + assertpy | hamcrest | 链式断言 |
| Testcontainers | testcontainers-python | docker-compose | 容器化集成测试 |
| JaCoCo | coverage | pytest-cov | 代码覆盖率 |
| Property-based Testing | hypothesis | — | 类似 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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Maven | uv | Poetry, hatch | uv 速度极快(Rust 实现),类似 Gradle 的体验 |
| Gradle (Kotlin DSL) | uv | PDM, flit | uv 的 pyproject.toml 类似 build.gradle.kts |
| Gradle Wrapper | uv | pipx | uv 自带 Python 版本管理 |
| BOM (Bill of Materials) | uv 的 resolution | — | uv 自动解析依赖版本 |
| Maven Central | PyPI | — | Python 包仓库 |
B.8 配置管理
| Java/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| application.yml | pydantic-settings | dynaconf | Pydantic Settings 提供类型安全的配置 + 环境变量支持 |
| HOCON | dynaconf | pydantic-settings | dynaconf 支持 YAML/TOML/ENV/.env 多种来源 |
@Value / @ConfigurationProperties | pydantic-settings | — | BaseSettings 类似 @ConfigurationProperties |
| Spring Profiles | pydantic-settings + env | dynaconf | 通过环境变量切换配置 |
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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Quartz | APScheduler | Celery | APScheduler 类似 Quartz 的轻量调度 |
| kotlinx.coroutines | asyncio | trio | Python 原生协程支持 |
| Spring @Async | Celery | arq, dramatiq | 分布式任务队列 |
| ScheduledExecutorService | asyncio.create_task | loopy | 协程任务 |
| Project Loom (虚拟线程) | asyncio + free-threaded [3.13] | — | Python 3.13 实验性自由线程 |
B.10 消息队列
| Java/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Kafka | kafka-python-ng | aiokafka, confluent-kafka | kafka-python-ng 是活跃维护的 fork |
| RabbitMQ | aio-pika | pika | aio-pika 原生异步 |
| Redis Streams | redis-py | — | redis-py 原生支持 Streams |
| AWS SQS | boto3 | aiobotocore | AWS 官方 SDK |
| JMS | confluent-kafka | — | Python 没有统一的 JMS 抽象 |
B.11 数据验证
| Java/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Bean Validation (Hibernate Validator) | pydantic | marshmallow, attrs | Pydantic V2 性能接近 Rust 实现 |
@NotNull / @Size / @Email | Field(..., min_length=1) / EmailStr | — | Pydantic 用类型注解声明约束 |
| Jakarta Validation | pydantic | — | 同上 |
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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Swagger / Springfox | FastAPI 自动生成 | — | FastAPI 从类型注解自动生成 OpenAPI 文档 |
| Spring REST Docs | FastAPI 自动生成 | — | 无需额外配置 |
| OpenAPI Generator | datamodel-code-generator | — | 从 OpenAPI spec 生成 Pydantic 模型 |
B.13 CLI 框架
| Java/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| picocli | typer | click | typer 基于 Typer(类型提示),最接近 picocli 的注解驱动体验 |
| JCommander | click | argparse (stdlib) | click 更成熟 |
| Spring Shell | click | rich-click | rich-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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Apache Commons Lang | more-itertools | toolz | itertools 的高级封装 |
| Apache Commons IO | pathlib (stdlib) | shutil (stdlib) | pathlib 提供面向对象的路径操作 |
| Guava | toolz | more-itertools | 函数式工具集 |
| Stream API | itertools + 列表推导式 | toolz | Python 没有专门的 Stream 类,但推导式更简洁 |
| Vavr | returns | result | 函数式 Either/Maybe/Result 类型 |
B.15 日期时间
| Java/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| java.time (JSR 310) | datetime + zoneinfo (stdlib) | pendulum | Python 3.9+ 的 zoneinfo 类似 java.time.ZoneId |
| ThreeTenBP | pendulum | arrow | pendulum API 最接近 Java 的 LocalDate/LocalDateTime |
| Joda-Time | pendulum | — | Joda-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/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Thymeleaf | Jinja2 | Mako | Jinja2 是 Python 模板的事实标准 |
| FreeMarker | Jinja2 | — | Jinja2 语法更简洁 |
| Pebble | Jinja2 | — | Pebble 本身就受 Jinja2 启发 |
B.17 缓存
| Java/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Caffeine | cachetools | functools.lru_cache (stdlib) | cachetools 的 TTLCache 类似 Caffeine |
| Spring Cache | cachetools | — | 装饰器方式缓存 |
| Redis (Spring Data Redis) | redis-py | — | 官方 Redis 客户端 |
| Ehcache | diskcache | — | 支持磁盘持久化的缓存 |
B.18 数据库迁移
| Java/Kotlin | Python 首选 | Python 备选 | 说明 |
|---|---|---|---|
| Flyway | Alembic | — | SQLAlchemy 配套迁移工具,类似 Flyway 的版本化迁移 |
| Liquibase | Alembic | yoyo-migrations | Alembic 更轻量 |
| Prisma Migrate | Alembic | — | Python 生态以 Alembic 为主 |
B.19 其他常用工具
| 功能 | Java/Kotlin | Python 首选 | 说明 |
|---|---|---|---|
| 环境变量 | System.getenv() | python-dotenv + os.environ | .env 文件加载 |
| 密码哈希 | Spring Security BCrypt | passlib | 多算法支持 |
| JWT | jjwt / java-jwt | PyJWT | JSON Web Token |
| HTTP 基础认证 | Spring Security | FastAPI + HTTPBasic | 内置支持 |
| CORS | Spring @CrossOrigin | FastAPI CORSMiddleware | 中间件方式 |
| WebSocket | Spring WebSocket | FastAPI WebSocket | 原生支持 |
| 依赖注入 | Spring DI / Koin | dependency-injector | Python DI 不是主流范式 |
| AOP | Spring AOP | 无成熟替代 | Python 用装饰器实现类似功能 |
| CSV 处理 | OpenCSV | pandas / csv (stdlib) | pandas 适合大数据量 |
| Excel 处理 | Apache POI | openpyxl | xlsx 读写 |
| PDF 生成 | iText | reportlab / WeasyPrint | reportlab 更底层 |
| 邮件 | JavaMail | aiosmtplib | 异步 SMTP 客户端 |
| 定时任务 | @Scheduled | APScheduler | 轻量级调度 |
附录 C: PEP 8 编码规范精要 vs Java/Kotlin 编码规范
PEP 8 是 Python 社区的编码风格指南,类似于 Java 的 Google Java Style Guide 或 Kotlin Coding Conventions。以下对比两者的关键差异。
C.1 命名规范
| 元素 | Python (PEP 8) | Java | Kotlin |
|---|---|---|---|
| 变量/函数/方法 | snake_case | camelCase | camelCase |
| 类/类型 | PascalCase | PascalCase | PascalCase |
| 常量 | UPPER_SNAKE_CASE | UPPER_SNAKE_CASE | UPPER_SNAKE_CASE / object |
| 模块/包 | snake_case | 小写 | 小写 |
| 私有成员 | _leading_underscore | private | private / _ |
| 受保护成员 | _single_underscore | protected | protected |
| 名称改写(伪私有) | __double_underscore | 无 | 无 |
| 魔术方法 | __dunder__ | 无 | operator |
| 接口 | 无接口概念,用 Protocol | PascalCase (I前缀可选) | PascalCase |
| 类型参数 | PascalCase | T, E, K, V | T, 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) | Java | Kotlin |
|---|---|---|---|
| 缩进 | 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-8 | UTF-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,但会导致 AttributeError 或 ImportError,且错误信息不直观。
# ❌ 循环依赖
# 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: bool 是 int 的子类
Java/Kotlin 思维: boolean 是独立类型,不能和 int 互操作。
Python 现实: bool 继承自 int,True == 1,False == 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 现实: * 和 ** 是解包运算符,args 和 kwargs 只是参数名约定。
# ❌ 以为 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 配置对比速查
| 特性 | uv | Poetry | Hatch |
|---|---|---|---|
| 安装速度 | 极快(Rust) | 中等 | 中等 |
| 锁文件 | uv.lock | poetry.lock | 无(依赖 pip) |
| 依赖解析 | Rust 实现 | Python 实现 | pip |
| Python 版本管理 | 内置 | 需要 pyenv | 需要 pyenv |
| 虚拟环境管理 | 内置 | 内置 | 内置 |
| 脚本管理 | uv run | poetry run | hatch run |
| 发布 | uv publish | poetry publish | hatch publish |
| 插件系统 | 无 | 丰富 | 丰富 |
| 学习曲线 | 低 | 中 | 中 |
| 推荐场景 | 新项目首选 | 已有 Poetry 项目 | 需要复杂构建矩阵 |
附录 F: 推荐学习资源与社区
F.1 官方文档(必读)
| 资源 | 链接 | 说明 |
|---|---|---|
| Python 官方文档 | docs.python.org/3/ | 最权威的参考,教程部分质量极高 |
| Python Tutorial | docs.python.org/3/tutorial/ | 官方教程,适合快速入门 |
| Python Language Reference | docs.python.org/3/reference… | 语言规范,深入理解语法细节 |
| Python Standard Library | docs.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 Tutorials | YouTube (免费) | 高质量视频教程,OOP/装饰器/生成器系列极佳 |
| ArjanCodes | YouTube (免费) | Python 设计模式、Clean Code 实践 |
| mCoding | YouTube (免费) | Python 底层原理、性能优化 |
| Real Python | realpython.com/ | 大量高质量教程和视频 |
| Talk Python to Me | Podcast | 每周 Python 生态访谈 |
F.4 社区和论坛
| 社区 | 链接 | 说明 |
|---|---|---|
| Python Discourse | discuss.python.org/ | 官方讨论论坛,PEP 讨论在这里进行 |
| r/Python | reddit.com/r/Python | Reddit Python 社区 |
| r/learnpython | reddit.com/r/learnpyth… | 适合提问和学习 |
| Stack Overflow | stackoverflow.com/questions/t… | 技术问答 |
| Python 中文社区 | www.python.org.cn/ | 中文 Python 社区 |
| Python Discord | discord.gg/python | 实时讨论 |
F.5 工具和库
| 类别 | 工具 | 说明 |
|---|---|---|
| 包管理 | uv | 速度最快的包管理器(Rust 实现) |
| 代码检查 | Ruff | 替代 flake8/pylint/isort/black 的全能工具(Rust 实现) |
| 类型检查 | mypy | 静态类型检查 |
| 格式化 | Ruff format | 替代 Black(Ruff 内置) |
| 测试 | pytest | 测试框架 |
| 交互式 | IPython | 增强的交互式解释器 |
| Notebook | Jupyter | 交互式笔记本 |
| 调试 | debugpy | VS Code Python 调试器后端 |
| 性能分析 | py-spy | 采样性能分析器(Rust 实现) |
| 依赖可视化 | pipdeptree | 查看依赖树 |
| 环境管理 | uv / pyenv | Python 版本管理 |
F.6 博客和新闻
| 资源 | 链接 | 说明 |
|---|---|---|
| What's New in Python | docs.python.org/3/whatsnew/ | 每个版本的变更日志 |
| Python Weekly | www.pythonweekly.com/ | 每周 Python 新闻邮件 |
| PyCoder's Weekly | pycoders.com/ | 每周 Python 文章和工具推荐 |
| Talk Python Podcast | talkpython.fm/ | Python 播客 |
| The Changelog | changelog.com/podcast | 开源技术播客(含 Python) |
| Ned Batchelder's Blog | nedbatchelder.com/blog/ | Python 核心开发者博客 |
| Anthony Shaw's Blog | blog.anthonyshaw.org/ | CPython 内部原理 |
| Martin Heinz's Blog | martinheinz.dev/ | Python 工程实践 |
F.7 PEP 精选阅读清单
对于想深入理解 Python 设计哲学的开发者,以下 PEP 最值得阅读:
| PEP | 标题 | 为什么值得读 |
|---|---|---|
| PEP 8 | Style Guide | 编码规范 |
| PEP 20 | The Zen of Python | Python 设计哲学(import this) |
| PEP 3107 | Function Annotations | 类型注解的起源 |
| PEP 484 | Type Hints | 类型提示规范 |
| PEP 572 | Assignment Expressions | 海象运算符 := |
| PEP 634 | Structural Pattern Matching | match/case 语法 |
| PEP 695 | Type Parameter Syntax | Python 3.12 泛型新语法 |
| PEP 703 | Making the GIL Optional | 自由线程(no-GIL) |
| PEP 636 | Pattern Matching Tutorial | 模式匹配教程 |
| PEP 484 | Type Hints | 类型提示完整规范 |
附录结束。回到 目录。