大家好,我是一个热爱折腾的 Python 开发者。今天想和大家聊聊我最近开源的一个小项目——everything2everything(简称 e2e-type-converter),以及它背后的故事。
一切的起源:被类型转换逼疯的夜晚
事情要从几个月前说起。当时我在做一个跨框架的机器学习项目,需要把用 PyTorch 训练好的模型部署到 TensorFlow Serving 上,同时还要用 NumPy 做一些数据预处理,最后用 Pandas 输出报表。听起来是不是很常见?但真正的噩梦在于——类型转换。
你可能也遇到过类似的情况:
# 从数据库拿到的数据是字符串列表
data = ["1", "2", "3"]
# 但模型需要的是 torch tensor
import torch
tensor = torch.tensor([int(x) for x in data]) # 手动转 int,再转 tensor
# 处理完后又想用 numpy 做统计
import numpy as np
arr = tensor.numpy() # 如果是 GPU 张量还得先 .cpu()
# 最后要存成 pandas DataFrame
import pandas as pd
df = pd.DataFrame(arr)
这还只是最简单的例子。当涉及到 cupy、xarray、jax 等更多库时,代码就会变得又臭又长,而且每个库都有自己的转换方法(.numpy()、.get()、np.asarray()……),记忆负担极重。
那个夜晚,我对着满屏的转换代码陷入了沉思:为什么 Python 没有一个统一的类型转换接口?
灵光一闪:万物皆可转
其实 Python 的内置类型转换函数(list()、str()、int() 等)已经很好用了,但它们只支持标准类型。如果我们能扩展它们,让它们支持所有第三方库类型,同时保持一致的调用方式,岂不是完美?
于是我决定写一个库,目标很简单:
- 统一接口:无论是转列表、字符串,还是转 numpy、torch,都像调用内置函数一样简单。
- 双向转换:任意类型之间可以互相转换,不需要手动处理中间格式。
- 类型安全:转换失败时给出明确的错误,而不是默默崩溃。
- 高性能:对重复转换进行缓存,避免浪费。
从原型到开源:everything2everything 诞生
一开始只是一个简单的 TypeConverter 类,支持 numpy↔torch 互转。后来随着需求增加,我陆续加入了 pandas、jax、tensorflow、xarray 等主流库的支持,并且设计了 通用转换方法 convert(obj, target_type),让转换变得前所未有的简单:
from everything2everything import TypeConverter
import numpy as np
arr = np.array([1, 2, 3])
tensor = TypeConverter.convert(arr, 'torch') # numpy → torch
arr2 = TypeConverter.convert(tensor, 'numpy') # torch → numpy
我还参考 Python 内置函数,提供了一组 e2e_* 便捷函数,用法和内置函数几乎一样:
from everything2everything import e2e_list, e2e_str, e2e_int
e2e_list(123) # [123]
e2e_str(None) # ""
e2e_int("42") # 42
e2e_list(np.array([1,2,3])) # [1,2,3]
你甚至可以直接用它替代原来的 list(),因为它的行为完全兼容。
技术亮点:不仅仅是封装
在开发过程中,我特别注意了以下几点:
- 智能依赖检测:如果用户没有安装 torch,调用相关转换时会抛出友好的提示,而不是直接
ImportError崩溃。 - 缓存机制:对于相同的输入,转换结果会被缓存(最大 1000 条),大幅提升重复转换的性能。
- GPU 设备管理:转换 torch/cupy 张量时自动处理设备(CPU/GPU),无需手动
.cpu()。 - 直接转换路径:对于一些常见组合(如 torch ↔ tensorflow),实现了直接从 A 到 B 的转换,避免绕路 numpy 带来的性能损耗。
用起来有多爽?
来看看实际对比吧。改造前的代码:
import numpy as np
import torch
import pandas as pd
# 从外部得到数据(可能是 numpy、torch、list 等)
data = np.array([[1,2,3], [4,5,6]])
# 想用 torch 训练
if isinstance(data, np.ndarray):
tensor = torch.from_numpy(data)
elif isinstance(data, torch.Tensor):
tensor = data
else:
tensor = torch.tensor(data)
# 训练后想保存为 pandas CSV
if isinstance(tensor, torch.Tensor):
arr = tensor.cpu().numpy()
else:
arr = np.array(tensor)
df = pd.DataFrame(arr)
改造后,一切都变得优雅:
import numpy as np
import torch
import pandas as pd
from everything2everything import TypeConverter
data = np.array([[1,2,3], [4,5,6]])
tensor = TypeConverter.convert(data, 'torch') # 一行转 torch
df = TypeConverter.convert(tensor, 'pandas') # 一行转 pandas
代码量减少 80%,可读性飙升!
社区的力量:欢迎来玩
现在 everything2everything 已经在 GitHub 上开源,支持 Python 3.7+,并且有详细的中英文文档(包含完整的 API 参考和示例)。如果你也被类型转换困扰过,不妨试试看:
pip install e2e-type-converter
项目地址:https://github.com/John-is-playing/everything2everything
如果你喜欢这个项目,欢迎点个 ⭐️ 支持一下!如果你有新的想法或发现了 bug,也欢迎提 issue 或 PR。一个人的力量有限,但一群人可以走得更远。
写在最后
回过头看,那个被转换代码逼疯的夜晚反而成了最好的动力。开源的意义大概就在于此:解决自己的痛点,顺便帮助有同样困扰的人。希望 everything2everything 能让你的 Python 开发更轻松一点。
Happy coding! 🚀
本文首发于我的个人博客,欢迎转载,请保留出处。
1万+



被折叠的 条评论
为什么被折叠?



