在当今快速发展的科技领域,Python 生态系统不断涌现出各种强大的工具和库,极大地提升了开发效率和数据处理能力。本文将介绍几款在数据建模、数据处理、数据验证、数据库管理和日志记录领域中备受瞩目的工具:Pydantic、Polars、Pandera、DuckDB 和 Loguru。这些工具不仅简化了开发流程,还通过其高性能和强大的功能,帮助开发者在复杂的数据场景中游刃有余。无论你是数据科学家、软件工程师还是数据分析师,这些工具都将成为你工具箱中的得力助手,助你构建更高效、更可靠的解决方案。
推荐阅读:
2025 超现代 Python 实用工具(一)
Pydantic
Pydantic
[1]
是一个功能强大的 Python 库,专门用于数据建模、解析和验证。它通过结合 Python 的类型注解和运行时类型检查,提供了一种更优雅、更安全的方式来组织和处理数据。与传统的使用字典或自定义数据类的方式相比,Pydantic 提供了一种更结构化、更可靠的解决方案,特别适合处理复杂的数据结构和外部输入(如 JSON、YAML 等)。
核心功能
-
数据建模
:Pydantic 允许开发者使用 Python 的类型注解定义数据模型。这些模型不仅清晰地描述了数据的结构,还提供了自动化的数据验证功能。
-
数据验证
:Pydantic 在数据赋值时会自动进行类型检查和验证,确保数据的完整性和一致性。如果数据不符合定义的模型,Pydantic 会抛出详细的错误信息,帮助开发者快速定位问题。
-
序列化与反序列化
:Pydantic 支持将数据模型与 JSON、YAML 等格式相互转换,使得数据的输入输出更加方便和高效。
-
自定义类型
:Pydantic 允许开发者创建自定义数据类型,并为其定义验证规则。这种灵活性使得 Pydantic 能够适应各种复杂的数据场景。
-
与 Python 类型系统无缝集成
:Pydantic 完全兼容 Python 的类型注解(PEP 484),并且支持高级类型(如
Optional
、
Union
、
List
等),使得数据模型的定义更加直观和强大。
优势
-
代码清晰性
:Pydantic 的数据模型通过类型注解清晰地描述了数据的结构,使得代码更易于理解和维护。
-
数据安全性
:Pydantic 的自动验证功能可以防止无效数据进入系统,减少运行时错误和数据异常。
-
开发效率
:Pydantic 的自动化功能(如数据验证、序列化)减少了开发者的手动工作量,提升了开发效率。
-
灵活性
:Pydantic 支持自定义类型和验证规则,能够适应各种复杂的数据场景。
Pydantic 与 Python 类型
Pydantic 是 Python 类型革命的重要组成部分。随着 Python 社区对静态类型和类型注解的重视,Pydantic 通过将类型系统与数据验证相结合,为 Python 开发者提供了一种更现代化、更安全的数据处理方式。
-
类型注解的普及
:Python 3.5 引入的类型注解(PEP 484)为 Pydantic 提供了基础。Pydantic 充分利用了这一特性,使得数据模型的定义更加直观和强大。
-
更安全的代码
:通过类型检查和数据验证,Pydantic 帮助开发者在早期发现潜在的错误,减少生产环境中的问题。
-
更清晰的代码结构
:Pydantic 的数据模型不仅描述了数据的结构,还通过类型注解提供了额外的文档信息,使得代码更易于理解和维护。
与字典和自定义数据类的对比
-
字典的局限性
:使用字典存储数据虽然灵活,但缺乏结构化和类型安全性,容易导致数据错误和代码难以维护。
-
自定义数据类的不足
:虽然 Python 的
dataclass
提供了一种定义数据类的方式,但它缺乏内置的验证功能,开发者需要手动编写验证逻辑。
-
Pydantic 的优势
:Pydantic 结合了字典的灵活性和数据类的结构化,同时提供了强大的验证功能,使得数据处理更加安全和高效。
Pydantic 使用 Python 类型提示来定义数据类型。试想一下,我们希望一个用户拥有 “name ”和 “id”,我们可以用一个字典对其进行建模:
import uuid
users = [
{'name': 'alpha', 'id': str(uuid.uuid4())},
{'name': 'beta'},
{'name': 'omega', 'id': 'invalid'}
]
我们也可以用 Pydantic 来建模--引入一个继承自
pydantic.BaseModel
的类:
import uuid
import pydantic
class User(pydantic.BaseModel):
name: str
id: str = None
users = [
User(name='alpha', 'id'= str(uuid.uuid4())),
User(name='beta'),
User(name='omega', id='invalid'),
]
Pydantic 的优势之一是验证--我们可以对用户 ID 进行一些验证--下面将检查
id
是否为有效的 GUID,否则将其设置为
None
:
import uuid
import pydantic
class User(pydantic.BaseModel):
name: str
id: str = None
@pydantic.validator('id')
def validate_id(cls, user_id:str ) -> str | None:
try:
user_id = uuid.UUID(user_id, version=4)
print(f"{user_id} is valid")
return user_id
except ValueError:
print(f"{user_id} is invalid")
return None
users = [
User(name='alpha', id= str(uuid.uuid4())),
User(name='beta'),
User(name='omega', id='invalid'),
]
[print(user) for user in users]
运行上述代码后,我们的 Pydantic 模型拒绝了我们的一个 ID - 我们的
omega
已拒绝了其原始 ID
invalid
并最终使用了
id=None
:
$ python pydantic_eg.py
45f3c126-1f50-48bf-933f-cfb268dca39a is valid
invalid is invalid
name='alpha' id=UUID('45f3c126-1f50-48bf-933f-cfb268dca39a')
name='beta' id=None
name='omega' id=None
这些 Pydantic 类型可以成为您 Python 程序中的原始数据结构(而不是字典)--让其他开发人员更容易理解发生了什么。
提示--你可以从 Pydantic 模型中生成 Typescript 类型--这样就可以在 Typescript 前端和 Python 后端共享相同的数据结构。
Polars
Polars
[2]
是一款高性能的 Python 数据处理工具,专门用于高效处理表格数据。作为 Pandas 或 Apache Spark 的替代工具,Polars 凭借其卓越的性能、灵活的功能和直观的语法,正在成为数据科学家和工程师的首选工具之一。无论是处理小型数据集还是超大规模数据,Polars 都能提供出色的表现。
核心特点
高性能
:
-
Polars 是用 Rust 语言编写的,充分利用了多核 CPU 的并行计算能力,能够以极快的速度处理数据。
-
与 Pandas 相比,Polars 在处理大规模数据时性能显著提升,尤其是在数据量超过内存容量时,Polars 依然能够高效运行。
查询优化
:
-
Polars 提供了强大的查询优化功能,能够将多个数据转换操作(如过滤、聚合、排序等)组合在一起,并自动优化执行计划。
-
这种“延迟执行”机制与 Pandas 的“即时执行”模式不同。Pandas 每次操作都会立即执行,而 Polars 会先构建一个执行计划,然后通过优化减少不必要的计算,从而大幅提升效率。
并行处理
:
-
Polars 内置并行处理功能,能够自动将任务分配到多个 CPU 核心上运行,充分利用硬件资源。
-
这种并行化能力使得 Polars 在处理大规模数据时表现出色,尤其适合需要高性能计算的场景。
处理大于内存的数据集
:
-
Polars 支持“流式处理”模式,能够分块读取和处理数据,从而轻松应对超过内存容量的数据集。
-
这一功能使得 Polars 在处理大数据时无需依赖分布式系统(如 Spark),同时保持高效和易用性。
直观的语法
:
-
Polars 的 API 设计简洁直观,许多操作与 Pandas 类似,但更加现代化和高效。
-
许多用户认为 Polars 的语法比 Pandas 更易于使用,尤其是在处理复杂数据操作时。
优势
-
性能卓越
:Polars 的性能远超 Pandas,尤其是在处理大规模数据时,速度提升可达数倍甚至数十倍。
-
内存效率高
:Polars 的内存管理更加高效,能够处理比内存更大的数据集,而不会导致系统崩溃或性能下降。
-
查询优化
:Polars 的延迟执行和查询优化机制使得复杂的数据操作更加高效,减少了不必要的计算开销。
-
易于迁移
:对于熟悉 Pandas 的用户来说,Polars 的学习曲线非常平缓,许多操作可以直接迁移。
-
开源与活跃社区
:Polars 是一个开源项目,拥有活跃的社区支持,开发者可以快速获得帮助并参与贡献。
与 Pandas 和 Spark 的对比
特性
|
Polars
|
Pandas
|
Spark
|
性能
|
极高(Rust 实现)
|
中等
|
高(分布式)
|
内存效率
|
支持流式处理
|
受限于内存
|
支持分布式处理
|
查询优化
|
支持延迟执行和优化
|
不支持
|
支持(Catalyst 优化)
|
语法
|
简洁直观
|
熟悉但略显老旧
|
复杂(Scala/Java)
|
适用场景
|
单机大规模数据处理
|
小型数据集
|
超大规模分布式数据
|
我们从一个有三列的数据集开始:
import polars as pl
df = pl.DataFrame({
'date': ['2025-01-01', '2025-01-02', '2025-01-03'],
'sales': [1000, 1200, 950],
'region': ['North', 'South', 'North']
})
下面我们将列创建和聚合合并为一个查询:
query = (
df
# start lazy evaluation - Polars won't execute anything until .collect()
.lazy()
# with_columns adds new columns
.with_columns(
[
# parse string to date
pl.col("date").str.strptime(pl.Date).alias("date"),
# add a new column with running total
pl.col("sales").cum_sum().alias("cumulative_sales"),
]
)
# column to group by
.group_by("region")
# how to aggregate the groups
.agg(
[
pl.col("sales").mean().alias("avg_sales"),
pl.col("sales").count().alias("n_days"),
]
)
)
# run the optimized query
print(query.collect())
shape: (2, 3)
┌────────┬───────────┬────────┐
│ region ┆ avg_sales ┆ n_days │
│ --- ┆ --- ┆ --- │
│ str ┆ f64 ┆ u32 │
╞════════╪═══════════╪════════╡
│ North ┆ 975.0 ┆ 2 │
│ South ┆ 1200.0 ┆ 1 │
└────────┴───────────┴────────┘
我们可以用 Polars 来解释我们的疑问:
print(query.explain())
AGGREGATE
[col("sales").mean().alias("avg_sales"), col("sales").count().alias("n_days")] BY [col("region"
)] FROM
DF ["date", "sales", "region"]; PROJECT 2/3 COLUMNS; SELECTION: Non
Tips: 可以使用
pl.DataFrame.to_pandas()
将 Polars DataFrame 转换为 Pandas DataFrame。这对于将基于 Pandas 的管道慢慢重构为基于 Polars 的管道非常有用。
Pandera
Pandera
[3]
是一款专为表格数据设计的轻量级数据质量检查工具,旨在帮助开发者和数据科学家在数据进入分析管道之前,快速发现并解决数据质量问题。与 Great Expectations 或简单的
assert
语句相比,Pandera 提供了更加灵活、直观且易于集成的方式来定义和验证数据模式,确保数据的完整性和一致性。
核心功能
数据模式定义
-
Pandera 允许用户为表格数据(如 Pandas DataFrame)定义明确的数据模式(Schema),包括列的类型、取值范围、唯一性约束等。
-
通过定义模式,Pandera 可以自动验证数据是否符合预期,从而在数据问题传播到下游分析之前将其捕获。
灵活的验证规则
-
Pandera 支持多种验证规则,例如数据类型检查、值范围检查、唯一性检查、正则表达式匹配等。
-
与 Pandas 无缝集成
-
Pandera 专为 Pandas DataFrame 设计,能够直接集成到现有的数据处理流程中,无需额外的学习成本。
-
清晰的错误报告
-
当数据不符合定义的模式时,Pandera 会提供详细的错误信息,帮助用户快速定位问题。
-
错误报告包括具体的列名、错误类型以及不符合规则的数据值。
支持复杂数据类型
-
Pandera 不仅支持基本的数据类型(如整数、浮点数、字符串),还支持复杂的数据类型(如日期时间、嵌套对象等)。
优势
-
轻量级与易用性
:Great Expectations 相比,Pandera 更加轻量级,易于集成到现有的 Python 数据生态系统中。
-
灵活性
:Pandera 支持自定义验证规则,能够满足各种复杂的业务需求。
-
清晰的错误反馈
:Pandera 的错误报告非常详细,能够帮助用户快速定位和修复数据问题。
-
与 Pandas 无缝集成
:Pandera 专为 Pandas 设计,能够直接应用于 DataFrame,无需额外的适配工作。
-
开源与社区支持
:Pandera 是一个开源项目,拥有活跃的社区支持,用户可以快速获得帮助并参与贡献。
与 Great Expectations 和
assert
语句的对比
特性
|
Pandera
|
Great Expectations
|
assert
语句
|
轻量级
|
是
|
否
|
是
|
灵活性
|
高(支持自定义规则)
|
高(功能更全面)
|
低(仅支持简单断言)
|
错误报告
|
详细
|
详细
|
简单
|
集成难度
|
低(专为 Pandas 设计)
|
中(需要额外配置)
|
低
|
适用场景
|
中小型数据项目
|
大型数据项目
|
简单验证
|
下面我们为销售数据创建一个模式,包括一些数据质量检查:
import polars as pl
import pandera as pa
from pandera.polars import DataFrameSchema, Column
schema = DataFrameSchema(
{
"date": Column(
pa.DateTime,
nullable=False,
coerce=True,
title="Date of sale"
),
"sales": Column(
int,
checks=[pa.Check.greater_than(0), pa.Check.less_than(10000)],
title="Daily sales amount",
),
"region": Column(
str,
checks=[pa.Check.isin(["North", "South", "East", "West"])],
title="Sales region",
),
}
)
现在,我们可以使用该模式验证数据:
data = pl.DataFrame({
"date": ["2025-01-01", "2025-01-02", "2025-01-03"],
"sales": [1000, 1200, 950],
"region": ["North", "South", "East"]
})
data = data.with_columns(pl.col("date").str.strptime(pl.Date, "%Y-%m-%d"))
print(schema(data))
shape: (3, 3)
┌────────────┬────────┬────────┐
│ date ┆ sales ┆ region │
│ --- ┆ --- ┆ --- │
│ datetime ┆ f64 ┆ str │
╞════════════╪════════╪════════╡
│ 2025-01-01 ┆ 1000.0 ┆ North │
│ 2025-01-02 ┆ 1200.0 ┆ South │
│ 2025-01-03 ┆ 950.0 ┆ North │
└────────────┴────────┴────────┘
当我们有
坏数据
时,Pandera 会引发异常:
data = pl.DataFrame({
"date": ["2025-01-01", "2025-01-02", "2025-01-03"],
"sales": [-1000, 1200, 950],
"region": ["North", "South", "East"]
})
data = data.with_columns(pl.col("date").str.strptime(pl.Date, "%Y-%m-%d"))
print(schema(data))
SchemaError: Column 'sales' failed validator number 0: failure case examples: [{'sales': -1000}]
提示 - Pandera 还提供了基于 Pydantic 风格类的 API,可以使用 Python 类型进行验证。
DuckDB
DuckDB
[4]
是一款高性能的嵌入式分析型数据库,专为高效执行 SQL 查询而设计。作为 SQLite、Polars 和 Pandas 的替代品,DuckDB 凭借其列式存储架构和优化的查询引擎,在处理分析型工作负载时表现出色。它特别适合用于数据科学、机器学习和大数据分析场景,能够以极快的速度处理大规模数据集。
核心特点
列式存储
:
-
DuckDB 采用列式存储架构,与传统的行式存储(如 SQLite)相比,能够显著提升分析型查询的性能。
-
列式存储特别适合用于聚合、过滤和扫描大量数据的场景,因为它只需要读取相关的列,而不是整行数据。
嵌入式设计
:
-
DuckDB 是一个嵌入式数据库,无需单独的服务器进程,可以直接集成到应用程序中。
-
它支持单文件数据库(类似于 SQLite),使得部署和管理更加简单。
高性能查询
:
-
DuckDB 的查询引擎经过高度优化,能够以极快的速度执行复杂的 SQL 查询。
-
兼容性
:
-
DuckDB 完全支持标准 SQL,并提供了丰富的扩展功能,例如窗口函数、嵌套查询和 JSON 支持。
-
它还可以直接读取和写入 Parquet、CSV 等常见数据格式,无需额外的数据导入步骤轻量级与易用性:
-
DuckDB 的安装和使用非常简单,只需几行代码即可开始使用。
-
它提供了 Python、R 等多种语言的 API,方便开发者集成到现有工作流中。
与 SQLite、Polars 和 Pandas 的对比
特性
|
DuckDB
|
SQLite
|
Polars
|
Pandas
|
存储架构
|
列式存储
|
行式存储
|
列式存储
|
内存存储
|
优化目标
|
分析型查询
|
事务性工作负载
|
数据处理与分析
|
数据处理与分析
|
性能
|
极高(列式存储)
|
中等(行式存储)
|
高(并行处理)
|
中等(单线程)
|
嵌入式支持
|
是
|
是
|
否
|
否
|
SQL 支持
|
完全支持
|
完全支持
|
不支持
|
不支持
|
适用场景
|
分析型查询
|
事务性应用
|
数据处理与分析
|
数据处理与分析
|
我们使用 CSV 和 Parquet 格式创建一些示例数据:
import duckdb
import polars as pl
sales = pl.DataFrame(
{
"date": ["2025-01-01", "2025-01-02", "2025-01-03"],
"product_id": [1, 2, 1],
"amount": [100, 150, 200],
}
).to_csv("sales.csv", index=False)
products = pl.DataFrame(
{"product_id": [1, 2], "name": ["Widget", "Gadget"], "category": ["A", "B"]}
).to_parquet("products.parquet")
下面我们对两种数据格式进行 SQL 查询:
con = duckdb.connect()
print(
con.execute(
"""
WITH daily_sales AS (
SELECT
date,
product_id,
SUM(amount) as daily_total
FROM 'sales.csv'
GROUP BY date, product_id
)
SELECT
s.date,
p.name as product_name,
p.category,
s.daily_total
FROM daily_sales s
JOIN 'products.parquet' p ON s.product_id = p.product_id
ORDER BY s.date, p.name
"""
).df()
)
date product_name category daily_total
0 2025-01-01 Widget A 100
1 2025-01-02 Gadget B 150
2 2025-01-03 Widget A 200
DuckDB 在处理大于内存的数据集时表现出色。它可以直接高效地查询 Parquet 文件,而无需先将其加载到内存中。
提示--使用 DuckDB 的 EXPLAIN 命令了解查询执行计划并优化查询。
Loguru
Loguru
[5]
是一个现代化、简洁且功能强大的 Python 日志记录库,旨在为开发者提供一种更简单、更直观的方式来记录日志。作为 Python 标准库
logging
模块和
structlog
的替代品,Loguru 通过减少配置复杂性、提供更友好的 API 和增强的功能,显著改善了日志记录的体验。它的设计理念是“让日志记录变得不再痛苦”,尤其适合那些希望快速上手并专注于核心开发的用户。
核心特点
零配置开箱即用
:
-
Loguru 无需复杂的配置即可直接使用。只需导入库并开始记录日志,所有默认设置都已优化,适合大多数场景。
-
与标准库
logging
模块相比,Loguru 避免了繁琐的 Handler、Formatter 和 Filter 配置。
单一日志记录器
:
-
Loguru 的核心理念是只使用一个全局日志记录器(
logger
),而不是为每个模块或组件创建多个日志记录器。
-
这种设计简化了日志管理,避免了因多个日志记录器导致的混乱和性能开销。
丰富的输出格式
:
-
Loguru 支持高度自定义的日志格式,包括时间戳、日志级别、文件名、行号等信息。
-
强大的日志处理功能
:
-
Loguru 提供了灵活的日志处理功能,例如日志轮转、压缩、异步写入等。
-
它还支持将日志输出到多种目标,如文件、控制台、电子邮件等。
异常捕获与回溯
:
-
Loguru 可以自动捕获并记录未处理的异常,并生成完整的堆栈回溯信息。
-
与标准库兼容
:
-
Loguru 构建在 Python 标准库
logging
模块之上,因此可以轻松替换现有的
logging.Logger
,而无需修改大量代码。
优势
-
简化日志记录
:Loguru 通过减少配置和提供更友好的 API,显著简化了日志记录的流程。
-
高性能
:Loguru 的设计注重性能,能够以较低的开销记录大量日志。
-
灵活性
:尽管 Loguru 提供了默认配置,但它仍然支持高度自定义,能够满足各种复杂的需求。
-
易用性
:Loguru 的 API 设计非常直观,即使是初学者也能快速上手。
-
社区支持
:Loguru 是一个开源项目,拥有活跃的社区支持,用户可以快速获得帮助并参与贡献。
与标准库
logging
和
structlog
的对比
特性
|
Loguru
|
标准库
logging
|
structlog
|
配置复杂性
|
零配置
|
高
|
中
|
API 友好性
|
高
|
低
|
中
|
性能
|
高
|
中
|
高
|
单一日志记录器
|
是
|
否
|
否
|
异常捕获
|
支持
|
不支持
|
部分支持
|
适用场景
|
快速开发、中小型项目
|
大型项目、复杂配置
|
结构化日志、大型项目
|
使用 Loguru 进行日志记录就像
from loguru import logger
一样简单:
from loguru import logger
logger.info("Hello, Loguru!")
2025-01-04 02:28:37.622 | INFO | __main__::3 - Hello, Loguru!
配置日志记录器只需调用一次
logger.add
即可完成。
我们可以配置如何将日志记录到
std.out
:
logger.add(
sys.stdout,
colorize=True,
format="{time} {message}",
level="INFO"
)
下面的代码会将日志配置到文件中:
logger.add(
"log.txt",
format="{time} {level} {message}",
level="DEBUG"
)
Tip: Loguru 支持通过
logger.add(“log.txt”,seralize=True)
参数将记录结构化为 JSON 格式。
Marimo
Marimo
[6]
是一种 Python 笔记本编辑器和格式
- 它是 Jupyter Lab 和 JSON Jupyter 笔记本文件格式的替代品。
与旧式的 Python 笔记本编写方式相比,Marimo 有多项改进:
-
更安全
- Marimo 笔记本单元格的执行基于变量引用而非顺序、
-
开发体验
- Marimo 为开发者提供了许多高质量的生活功能、
-
互动
- Marimo 提供类似网络应用程序的互动体验。
Marimo 还提供了反应功能--当单元格的输入发生变化时,可以重新执行单元格。对于某些笔记本来说,这可能是一把双刃剑,因为改变调用会产生副作用,如查询应用程序接口或数据库。
Marimo 笔记本存储为纯 Python 文件,这意味着:Git diffs 是有意义的,笔记本可以作为脚本执行。
下面是 Marimo 笔记本格式的示例:
import marimo
__generated_with = "0.10.12"
app = marimo.App(width="medium")
@app.cell
def _():
import pandas as pd
def func():
return None
print("hello")
return func, pd
if __name__ == "__main__":
app.run()
提示 - Marimo 与 GitHub Copilot 和 Ruff 代码格式化集成。
Pydantic 是一个现代化的 Python 数据工具,通过其强大的数据建模和验证功能,帮助开发者构建更清晰、更安全的代码。随着 Python 类型革命的推进,Pydantic 正在成为 Python 开发中不可或缺的一部分,特别是在需要处理复杂数据结构的场景中。
Polars 是一款现代化的高性能数据处理工具,凭借其查询优化、并行处理和流式处理能力,正在成为 Pandas 和 Spark 的有力替代品。无论是处理小型数据集还是超大规模数据,Polars 都能提供卓越的性能和直观的语法。如果你正在寻找一个更快、更高效的数据处理工具,Polars 无疑是你的理想选择。
Pandera 是一款轻量级且功能强大的数据质量检查工具,特别适合用于验证表格数据的完整性和一致性。通过定义明确的数据模式,Pandera 能够在数据问题传播到下游分析之前将其捕获,从而显著提升数据质量。无论是数据清洗、数据管道,还是自动化测试,Pandera 都能成为你的得力助手。如果你正在寻找一个简单易用且功能强大的数据验证工具,Pandera 无疑是你的理想选择。
DuckDB 是一款专为分析型查询设计的高性能嵌入式数据库,凭借其列式存储架构和优化的查询引擎,能够以极快的速度处理大规模数据集。与 SQLite 的事务性优化不同,DuckDB 专注于分析型工作负载,特别适合用于数据科学、机器学习和大数据分析场景。如果你正在寻找一个轻量级、高性能且易于使用的 SQL 数据库,DuckDB 无疑是你的理想选择。
Loguru 是一个现代化、简洁且功能强大的日志记录库,通过其零配置、单一日志记录器和丰富的功能,显著简化了 Python 日志记录的流程。无论是快速开发、调试还是替代标准库
logging
,Loguru 都能提供卓越的体验。如果你正在寻找一个更简单、更直观的日志记录工具,Loguru 无疑是你的理想选择。
参考资料
[1]
Pydantic
:
https://pydantic-docs.helpmanual.io/
[2]
Polars
:
https://www.pola.rs/
[3]
Pandera
:
https://pandera.readthedocs.io/
[4]
DuckDB
:
https://duckdb.org/
[5]
Loguru
:
https://github.com/Delgan/loguru
[6]
Marimo
:
https://marimo.io/