name: fiftyone-code-style description: 编写遵循FiftyOne官方规范的Python代码。适用于为FiftyOne做贡献、开发插件或编写与FiftyOne代码库集成的代码时使用。
FiftyOne 代码风格指南
模块模板
"""
模块描述。
| Copyright 2017-2025, Voxel51, Inc.
| `voxel51.com <https://voxel51.com/>`_
|
"""
# 标准库
import logging
import os
# 第三方库
import numpy as np
# eta (Voxel51工具库)
import eta.core.utils as etau
# FiftyOne
import fiftyone.core.fields as fof
import fiftyone.core.labels as fol
import fiftyone.core.utils as fou
logger = logging.getLogger(__name__)
def public_function(arg):
"""公共API函数。"""
return _helper(arg)
def _helper(arg):
"""私有辅助函数(下划线前缀)。"""
return arg
导入组织
分为四组,每组内按字母顺序排列:
| 组别 | 示例 |
|---|---|
| 1. 标准库 | import logging, import os |
| 2. 第三方库 | import numpy as np, from PIL import Image |
| 3. eta包 | import eta.core.utils as etau |
| 4. FiftyOne | import fiftyone.core.labels as fol |
FiftyOne 导入别名
| 模块 | 别名 |
|---|---|
fiftyone |
fo |
fiftyone.core.labels |
fol |
fiftyone.core.fields |
fof |
fiftyone.core.media |
fom |
fiftyone.core.storage |
fos |
fiftyone.core.utils |
fou |
fiftyone.utils.image |
foui |
fiftyone.utils.video |
fouv |
文档字符串(Google风格)
函数文档字符串
def get_operator(operator_uri, enabled=True):
"""获取指定URI的操作符。
Args:
operator_uri: 操作符URI
enabled (True): 是否仅包含启用的操作符(True)、仅包含禁用的操作符(False)或所有操作符("all")
Returns:
一个 :class:`fiftyone.operators.Operator` 实例
Raises:
ValueError: 如果找不到操作符
"""
类文档字符串
class ImageMetadata(Metadata):
"""用于存储图像样本元数据的类。
Args:
size_bytes (None): 图像在磁盘上的大小,单位字节
mime_type (None): 图像的MIME类型
width (None): 图像宽度,单位像素
height (None): 图像高度,单位像素
"""
关键模式:
- 带默认值的参数:
参数名 (默认值): 描述 - 多行描述:缩进续行
- 交叉引用:
:class:fiftyone.module.Class``
私有函数
# 公共API委托给私有辅助函数
def build_for(cls, path_or_url, mime_type=None):
"""为给定文件构建Metadata对象。"""
if path_or_url.startswith("http"):
return cls._build_for_url(path_or_url, mime_type=mime_type)
return cls._build_for_local(path_or_url, mime_type=mime_type)
# 私有:下划线前缀,目的明确
def _build_for_local(cls, filepath, mime_type=None):
"""本地文件内部辅助函数。"""
size_bytes = os.path.getsize(filepath)
if mime_type is None:
mime_type = etau.guess_mime_type(filepath)
return cls(size_bytes=size_bytes, mime_type=mime_type)
延迟导入
使用 fou.lazy_import() 处理可选/重量级依赖:
# 基本延迟导入
o3d = fou.lazy_import("open3d", callback=lambda: fou.ensure_package("open3d"))
# 使用ensure_import处理pycocotools
mask_utils = fou.lazy_import(
"pycocotools.mask", callback=lambda: fou.ensure_import("pycocotools")
)
# 内部模块延迟导入
fop = fou.lazy_import("fiftyone.core.plots.plotly")
何时使用:
- 重量级包(open3d, tensorflow, torch)
- 可选依赖(pycocotools)
- 防止循环导入
防护模式
使用 hasattr() 进行条件行为检查:
# 检查可选属性
if hasattr(label, "confidence"):
if label.confidence is None or label.confidence < threshold:
label = label.__class__()
# 检查配置属性
if hasattr(eval_info.config, "iscrowd"):
crowd_attr = eval_info.config.iscrowd
else:
crowd_attr = None
# 动态状态初始化
if not hasattr(pb, "_next_idx"):
pb._next_idx = 0
pb._next_iters = []
错误处理
使用 logger.warning() 处理非致命错误:
# 非致命:警告并继续
try:
for target in fo.config.logging_debug_targets.split(","):
if logger_name := target.strip():
loggers.append(logging.getLogger(logger_name))
except Exception as e:
logger.warning(
"解析日志调试目标'%s'失败:%s",
fo.config.logging_debug_targets,
e,
)
# 缺少可选导入
try:
import resource
except ImportError as e:
if warn_on_failure:
logger.warning(e)
return
# 优雅降级
try:
mask = etai.render_instance_image(dobj.mask, dobj.bounding_box, frame_size)
except:
width, height = frame_size
mask = np.zeros((height, width), dtype=bool)
避免冗余实现
在编写新函数之前,检查FiftyOne是否已提供该功能。
fiftyone.core.utils (fou) 中的常用工具
| 函数 | 用途 |
|---|---|
fou.lazy_import() |
延迟模块加载 |
fou.ensure_package() |
安装缺失包 |
fou.ensure_import() |
验证导入可用性 |
fou.extract_kwargs_for_class() |
为类拆分关键字参数 |
fou.load_xml_as_dict() |
解析XML为字典 |
fou.get_default_executor() |
获取线程池执行器 |
eta.core.utils (etau) 中的常用工具
| 函数 | 用途 |
|---|---|
etau.guess_mime_type() |
检测文件MIME类型 |
etau.is_str() |
检查是否为字符串 |
etau.ensure_dir() |
创建目录(如果缺失) |
etau.ensure_basedir() |
创建父目录 |
etau.make_temp_dir() |
创建临时目录 |
编写新代码前
-
搜索现有模块 查找类似功能:
grep -r "def 你的函数名" fiftyone/ grep -r "相似关键字" fiftyone/core/utils.py -
首先检查这些模块:
fiftyone.core.utils- 通用工具fiftyone.core.storage- 文件/云操作fiftyone.utils.*- 格式特定工具eta.core.utils- 底层辅助函数
-
冗余实现的红旗:
- 文件路径操作 → 检查
os.path或etau - JSON/字典操作 → 检查
eta.core.serial - 图像操作 → 检查
fiftyone.utils.image - 类型检查 → 检查
etau.is_str()等
- 文件路径操作 → 检查
代码验证清单
提交代码前,验证:
风格合规性
- [ ] 模块有版权头部文档字符串
- [ ] 导入分4组(标准库 → 第三方 → eta → fiftyone)
- [ ] 每组内导入按字母顺序排列
- [ ] FiftyOne导入使用标准别名(fol, fou等)
- [ ] 日志记录器定义为
logger = logging.getLogger(__name__) - [ ] Google风格文档字符串,包含Args/Returns/Raises
- [ ] 私有函数以
_为前缀
代码质量
- [ ] 无冗余实现(已检查现有工具)
- [ ] 重量级导入使用
fou.lazy_import() - [ ] 可选属性使用
hasattr()防护 - [ ] 非致命错误使用
logger.warning() - [ ] 无裸
except:(尽可能指定异常类型)
测试
# 运行代码检查
pylint fiftyone/你的模块.py
# 检查风格
black --check fiftyone/你的模块.py
# 运行测试
pytest tests/unittests/你的测试.py -v
快速参考
| 模式 | 约定 |
|---|---|
| 模块结构 | 文档字符串 → 导入 → 日志记录器 → 公共 → 私有 → 类 |
| 私有函数 | _前缀,模块级别,小而专注 |
| 文档字符串 | Google风格,包含Args/Returns/Raises |
| 错误处理 | try/except + logger.warning() 处理非致命错误 |
| 延迟导入 | fou.lazy_import() 用于可选依赖 |
| 防护模式 | hasattr() 检查条件行为 |
| 导入别名 | fol, fof, fom, fos, fou |
| 常量 | 大写字母,私有:_大写字母 |
| 类继承 | 显式 class Foo(object): |
| 冗余检查 | 首先搜索 fou, etau, 现有模块 |