Python避免循环依赖

Python避免循环依赖

这句话的意思是,在 Python(或其他支持模块化编程的语言)中,import 语句的顺序应该按照 高层模块(更抽象、依赖更少的模块)到低层模块(更具体、依赖更多的模块) 的方式进行组织,否则容易导致 循环导入(circular import) 的问题。


1. 什么是高层模块和低层模块?

  • 高层模块:通常是应用逻辑层,依赖较少,提供更通用的功能。例如,控制器(Controller)、业务逻辑层(Service)。
  • 低层模块:通常是基础库、数据访问层,依赖更多的外部库。例如,数据库模型(Model)、工具函数(Utils)。

举例来说:

# 高层模块(controller.py)
from service import process_data

def handle_request():
    return process_data()
# 低层模块(service.py)
from model import fetch_data

def process_data():
    data = fetch_data()
    return data.upper()
# 更低层模块(model.py)
def fetch_data():
    return "database result"

在这个结构中:

  • controller.py 依赖 service.py
  • service.py 依赖 model.py
  • model.py 没有进一步的依赖

这是一种合理的依赖顺序,高层模块不会 import 低层模块后,又被低层模块 import 回去。


2. 为什么不建议从低层 import 高层?

如果低层模块(例如 model.py)导入了高层模块(例如 controller.py),会形成 循环 import

# model.py
from controller import handle_request  # ❌ 低层导入高层,形成循环导入

这会导致 Python 在加载模块时:

  1. controller.py 加载 service.pyservice.py 加载 model.py
  2. model.py 试图加载 controller.py,但 controller.py 还没完全初始化
  3. 运行时报错:
    ImportError: cannot import name 'handle_request' from partially initialized module 'controller'
    

3. 如何避免循环 import?

✅ 正确的 import 顺序

按照 高层 → 低层 方式组织:

  1. 标准库
  2. 第三方库
  3. 自定义的高层模块
  4. 自定义的低层模块
# controller.py (高层)
import json  # 标准库
import requests  # 第三方库
from service import process_data  # 业务逻辑层

def handle_request():
    return process_data()
# service.py (中层)
from model import fetch_data  # 依赖底层模块

def process_data():
    data = fetch_data()
    return json.dumps({"result": data})
# model.py (低层)
import sqlite3  # 标准库

def fetch_data():
    return "database result"

✅ 解决循环 import 的方法

如果必须在 model.py 里使用 controller.py 的某些功能,可以用 延迟导入(import inside function)

# model.py
def fetch_data():
    from controller import handle_request  # 延迟导入,避免循环
    return "database result"

这样 controller.py 不会在 model.py 被加载时立即导入,而是等到 fetch_data() 运行时才导入 controller,从而避免循环 import。


总结

错误的 import 方式(容易循环导入):

# 低层模块(model.py)
from controller import handle_request  # ❌ 低层不应 import 高层

推荐的 import 方式(避免循环导入):

  1. 始终从高层向低层 import
  2. 低层模块避免 import 高层模块
  3. 必要时使用函数内 import(延迟导入)
  4. 考虑将共享逻辑放到独立的 utils.py

这就是「顶部的 import 更建议从高层模块向低层 import」的含义。

本文作者:Gold_stein

本文链接:https://www.cnblogs.com/smartljy/p/18676535

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Gold_stein  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
历史上的今天:
2024-01-17 P8650 [蓝桥杯 2017 省 A] 正则问题
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 逃离地面 RAD & 三浦透子
逃离地面 - RAD & 三浦透子
00:00 / 00:00
An audio error has occurred.

作词 : 野田洋次郎

作曲 : 野田洋次郎

空飛ぶ羽根と引き換えに 繋ぎ合う手を選んだ僕ら

それでも空に魅せられて 夢を重ねるのは罪か

夏は秋の背中を見て その顔を思い浮かべる

憧れなのか、恋なのか 叶わぬと知っていながら

重力が眠りにつく 1000年に一度の今日

太陽の死角に立ち 僕らこの星を出よう

彼が眼を覚ました時 連れ戻せない場所へ

「せーの」で大地を蹴って ここではない星へ

行こう

もう少しで運命の向こう もう少しで文明の向こう

もう少しで運命の向こう もう少しで

夢に僕らで帆を張って 来たるべき日のために夜を超え

いざ期待だけ満タンで あとはどうにかなるさと 肩を組んだ

怖くないわけない でも止まんない

ピンチの先回りしたって 僕らじゃしょうがない

僕らの恋が言う 声が言う

「行け」と言う