lazy-import-refactor

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Lazy Import Refactor

延迟导入重构

Module-level
import torch
/
import tensorflow
等 heavy native dependency を function-internal lazy import に移行するための手順 + test 副作用予測 + CI-equivalent 検証要件。
将模块级的
import torch
/
import tensorflow
等重型原生依赖迁移至函数内部延迟导入的步骤 + 测试副作用预测 + 等效CI验证要求。

When to Use

适用场景

  • import <library>
    単体で SIGSEGV (CUDA driver 不在 + triton C-ext segfault 等)
  • 起動時間短縮のため重い import を遅延させたい
  • WebAPI 専用利用者に heavy native dep を不要にしたい
  • 上流 lib の lazy import 化を下流プロジェクトから依頼する設計検討
該当した実例: Linux + triton + CUDA driver 不在で
import <ML ライブラリ>
が SIGSEGV → torch / transformers の module-level import 排除で恒久解消したケースがある
  • 仅执行
    import <library>
    就触发SIGSEGV(例如缺少CUDA驱动 + triton C扩展段错误等情况)
  • 为缩短启动时间而需要延迟重型依赖的导入
  • 希望让仅使用WebAPI的用户无需安装重型原生依赖
  • 考虑从下游项目向上游库提出延迟导入改造的设计需求
实际案例:在Linux + triton + 缺少CUDA驱动的环境中,
import <机器学习库>
触发SIGSEGV → 通过移除torch/transformers的模块级导入彻底解决问题

Step 1: Pre-flight grep — 影響範囲完全洗い出し

步骤1:预检查 grep — 全面排查影响范围

Module-level import 全件 (col 0 のみ):
bash
find src -name "*.py" | while read f; do
  awk -v fn="$f" '/^(import torch|from torch|import torchvision|from torchvision|import tensorflow|from tensorflow)/{print fn":"NR":"$0}' "$f"
done
テスト側の module attribute patch 全件:
bash
find tests -name "*.py" | while read f; do
  awk -v fn="$f" '/@patch.*\.(torch|tensorflow|jax)|patch\.object.*\.(torch|tensorflow|jax)/{print fn":"NR":"$0}' "$f"
done
Module-level import を関数内に移すと、その module の
module.torch
属性が消滅する。test 側で
@patch("path.to.module.torch")
を使用している箇所は全件 AttributeError で壊れる
ため、事前 grep が必須。
所有模块级导入(仅第0列):
bash
find src -name "*.py" | while read f; do
  awk -v fn="$f" '/^(import torch|from torch|import torchvision|from torchvision|import tensorflow|from tensorflow)/{print fn":"NR":"$0}' "$f"
done
测试侧所有模块属性补丁:
bash
find tests -name "*.py" | while read f; do
  awk -v fn="$f" '/@patch.*\.(torch|tensorflow|jax)|patch\.object.*\.(torch|tensorflow|jax)/{print fn":"NR":"$0}' "$f"
done
将模块级导入移至函数内部后,该模块的
module.torch
属性会消失。测试侧使用
@patch("path.to.module.torch")
的所有位置都会因AttributeError而失效
,因此必须提前进行grep排查。

Step 2: Refactor パターン

步骤2:重构模式

python
undefined
python
undefined

Before (module-level)

重构前(模块级)

import torch
class Foo: def bar(self, x: torch.Tensor) -> torch.Tensor: with torch.no_grad(): ...
import torch
class Foo: def bar(self, x: torch.Tensor) -> torch.Tensor: with torch.no_grad(): ...

After (TYPE_CHECKING + function-internal)

重构后(TYPE_CHECKING + 函数内部)

from future import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING: import torch
class Foo: def bar(self, x: torch.Tensor) -> torch.Tensor: import torch # lazy load with torch.no_grad(): ...

**必須事項:**
- `from __future__ import annotations` を冒頭に追加 (型ヒントを文字列化、runtime evaluation 回避)
- runtime で使う関数の冒頭で `import torch` を再宣言
- module-level の bare `import torch` は削除
from future import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING: import torch
class Foo: def bar(self, x: torch.Tensor) -> torch.Tensor: import torch # 延迟加载 with torch.no_grad(): ...

**必填事项:**
- 在文件开头添加`from __future__ import annotations`(将类型提示字符串化,避免运行时求值)
- 在运行时使用的函数开头重新声明`import torch`
- 删除模块级的裸`import torch`

Step 3: Test 副作用対応

步骤3:测试副作用处理

python
undefined
python
undefined

Before

重构前

@patch("your_package.core.heavy_deps.torch") def test_foo(mock_torch): ...
@patch("your_package.core.heavy_deps.torch") def test_foo(mock_torch): ...

After

重构后

def test_foo(monkeypatch): import sys from unittest.mock import MagicMock mock_torch = MagicMock() monkeypatch.setitem(sys.modules, "torch", mock_torch) ...

詳細パターン (context manager mock, cuda.is_available, getattr-based access 等) は [test-side-effects.md](test-side-effects.md) 参照。
def test_foo(monkeypatch): import sys from unittest.mock import MagicMock mock_torch = MagicMock() monkeypatch.setitem(sys.modules, "torch", mock_torch) ...

详细模式(上下文管理器mock、cuda.is_available、基于getattr的访问等)请参考[test-side-effects.md](test-side-effects.md)。

Step 4: Verification — CI-equivalent filter で必ず検証

步骤4:验证 — 务必使用等效CI过滤器进行验证

プロジェクトの testing ルール(例:
rules/testing.md
の "CI-equivalent filter で local 検証する" セクション)を参照。
-m unit
等の短縮 filter では検証不充分
(本 SKILL の存在理由 — サブモジュール側の marker 差分が短縮 filter では再現できず下流 CI で初検出された実例がある)。CI workflow の filter を完全一致で local 実行する。
モノレポ内の独立パッケージ (submodule 等) の場合:
bash
cd <package-path>
uv run pytest -m "not downloads_and_runs_model and not calls_real_webapi"
请参考项目的测试规则(例如:
rules/testing.md
中的“使用等效CI过滤器进行本地验证”章节)。
使用
-m unit
等简化过滤器无法充分验证
(本技巧的存在原因——子模块的标记差异无法通过简化过滤器复现,曾出现过在下游CI中才首次发现问题的案例)。请完全匹配CI工作流的过滤器进行本地执行。
对于单体仓库中的独立包(如子模块):
bash
cd <package-path>
uv run pytest -m "not downloads_and_runs_model and not calls_real_webapi"

Step 5: Cross-repo PR 順序

步骤5:跨仓库PR顺序

submodule で利用される lib の場合:
  1. lib 側で fix + CI-equivalent test pass を確認
  2. lib 側 PR 起票 → merge 待ち
  3. merge 後、下流プロジェクトで submodule pin 更新 PR 起票
順序を逆にすると下流 CI で初検出され、hot-fix PR 連鎖が必要になる。
gh pr create
実行時、kit の submodule pre-PR check hook (
hook_pre_pr_submodule_check.py
) が導入されていれば、submodule 変更を含む PR で CI-equivalent test 実行確認を要求する (bypass は
CI-EQUIV-TESTED
marker comment)。
如果是被子模块使用的库:
  1. 在库侧修复并确认等效CI测试通过
  2. 在库侧提交PR → 等待合并
  3. 合并后,在下游项目提交更新子模块版本的PR
如果顺序颠倒,会在下游CI中首次发现问题,导致需要连续提交热修复PR。
执行
gh pr create
时,如果已引入kit的子模块PR前检查钩子(
hook_pre_pr_submodule_check.py
),则包含子模块变更的PR会要求确认已执行等效CI测试(可通过添加
CI-EQUIV-TESTED
标记注释绕过)。

Anti-patterns

反模式

  • module-level の上位 lib import:
    from transformers.models.clip import CLIPProcessor
    は transformers が torch を eager load するため lazy 化が必要。直接
    import torch
    でなくても heavy native dep を引き連れる import は全て対象
  • TYPE_CHECKING 内のみで対応:
    cast(<heavy_lib>.Type, ...)
    isinstance(x, <heavy_lib>.Type)
    のような runtime 評価が必要な箇所では完全には escape できない →
    from __future__ import annotations
    で型ヒントの string 化と、関数内
    import
    の両方を必須とする
  • subprocess regression test の欠落: lazy import 化が効いているか検証する test を同 PR で追加する。fresh interpreter での
    import <lib>; assert 'torch' not in sys.modules
    パターンを推奨 (subprocess 経由で session 汚染を回避)
  • -m unit
    での local 検証
    : CI が独立 marker (
    standard
    等) を使う場合、必ず CI 設定の filter で検証する
  • 模块级导入上层库
    from transformers.models.clip import CLIPProcessor
    会导致transformers提前加载torch,因此需要进行延迟导入改造。即使不是直接
    import torch
    ,只要会引入重型原生依赖的导入都属于改造对象
  • 仅在TYPE_CHECKING中处理:对于
    cast(<heavy_lib>.Type, ...)
    isinstance(x, <heavy_lib>.Type)
    这类需要运行时求值的场景,无法完全规避问题 → 必须同时使用
    from __future__ import annotations
    将类型提示字符串化,以及在函数内添加
    import
    语句
  • 缺少子进程回归测试:需在同一PR中添加验证延迟导入是否生效的测试。推荐使用
    import <lib>; assert 'torch' not in sys.modules
    模式(通过子进程执行,避免会话污染)
  • 使用
    -m unit
    进行本地验证
    :如果CI使用独立标记(如
    standard
    等),务必使用CI配置中的过滤器进行验证