循环依赖 - 最佳解决方案?
我有三个文件:a.py
、b.py
和c.py
。
这三个文件在不同的文件夹里(我们称它们为a_dir
、b_dir
和c_dir
)。最开始我只有两个文件a.py
和b.py
。b.py
的内容是这样的:
from root_dir.a_dir import a
...
do something
...
这样一切都正常。但当我创建了第三个文件c.py
,并像这样在a.py
中引入它:
from root_dir.c_dir import c
...
do something
...
我开始收到错误提示,Python无法在b.py
中导入a
。所以我想这可能是循环依赖的问题?然后我改变了a.py
中的导入方式,像这样:
def method_with_c_import(s):
from root_dir.c_dir import c
...
do something inside method
...
所以我只在需要的地方使用了导入(我在其他地方不需要这个导入,而且那个方法在b.py
中没有被使用)。
但这样做是最好的方法吗?或者有没有更好的解决方案?
根据要求的错误追踪(如果我把在a.py
中添加的导入放在文件开头的方法外面,就会出现这个错误):
Traceback (most recent call last):
File "/home/oerp/openerp70/openerp/server/openerp/cli/server.py", line 97, in preload_registry
db, registry = openerp.pooler.get_db_and_pool(dbname,update_module=update_module)
File "/home/oerp/openerp70/openerp/server/openerp/pooler.py", line 33, in get_db_and_pool
registry = RegistryManager.get(db_name, force_demo, status, update_module)
File "/home/oerp/openerp70/openerp/server/openerp/modules/registry.py", line 203, in get
update_module)
File "/home/oerp/openerp70/openerp/server/openerp/modules/registry.py", line 233, in new
openerp.modules.load_modules(registry.db, force_demo, status, update_module)
File "/home/oerp/openerp70/openerp/server/openerp/modules/loading.py", line 350, in load_modules
force, status, report, loaded_modules, update_module)
File "/home/oerp/openerp70/openerp/server/openerp/modules/loading.py", line 256, in load_marked_modules
loaded, processed = load_module_graph(cr, graph, progressdict, report=report, skip_modules=loaded_modules, perform_checks=perform_checks)
File "/home/oerp/openerp70/openerp/server/openerp/modules/loading.py", line 159, in load_module_graph
load_openerp_module(package.name)
File "/home/oerp/openerp70/openerp/server/openerp/modules/module.py", line 415, in load_openerp_module
getattr(sys.modules['openerp.addons.' + module_name], info['post_load'])()
File "/home/oerp/openerp70/openerp/server/openerp/addons/web/http.py", line 628, in wsgi_postload
openerp.wsgi.register_wsgi_handler(Root())
File "/home/oerp/openerp70/openerp/server/openerp/addons/web/http.py", line 517, in __init__
self.load_addons()
File "/home/oerp/openerp70/openerp/server/openerp/addons/web/http.py", line 580, in load_addons
m = __import__('openerp.addons.' + module)
File "/home/oerp/openerp70/openerp/server/openerp/modules/module.py", line 133, in load_module
mod = imp.load_module('openerp.addons.' + module_part, f, path, descr)
File "/home/oerp/openerp70/openerp/addons/ambulance_system/__init__.py", line 24, in <module>
import report
File "/home/oerp/openerp70/openerp/addons/ambulance_system/report/__init__.py", line 15, in <module>
import marketing_clinic_report
File "/home/oerp/openerp70/openerp/addons/ambulance_system/report/marketing_clinic_report.py", line 6, in <module>
from ambulance_system.model import new_medical_card as nmc
ImportError: cannot import name new_medical_card
附注:这个错误是针对我在问题中提到的文件b.py
(当我按照上面所写的在a.py
中进行更改后出现的错误追踪)。
更新 目录的优先导入:
import generic #c.py directory
import model #a.py directory
import report #b.py directory
更新2
根据要求提供一个示例以重现问题(new_medical_card.py
是a.py
,marketing_clinic_report.py
是b.py
,generic.py
是c.py
):
模块文件和目录结构:
ambulance_system/:
- generic/generic.py
- model/new_medical_card.py
- report/marketing_clinic_report.py
三个文件中的导入:
generic.py
:
import math
new_medical_card.py
:
from openerp.osv import osv, orm, fields
import tools
from tools.translate import _
import time
from datetime import date, datetime, timedelta
ambulance_system.model.generic import generic as grc #This one produces error
marketing_clinic_report.py
:
import time
from report import report_sxw
from ambulance_system.model import new_medical_card as nmc
根据要求更新3 初始化导入:
我已经展示了主要的初始化文件(根目录中的那个 - ambulance_system,但为了清晰起见,这里也会再贴一次):
__init__.py
目录的优先导入:
import generic #c.py directory
import model #a.py directory
import report #b.py directory
__init__.py
用于generic目录(c.py
):
import generic
__init__.py
用于model目录(a.py
):
import new_medical_card
import medical_card_segment_res
import medical_card
import res_partner
import model_request_access
import new_medical_card_requirement
import medical_card_rule
import hr_department_team
__init__.py
用于report目录(b.py
):
import card_field_report
import medical_card_field_report
import medical_card_reject_report
import new_medical_card_reject_report
import new_medical_card_field_report
import old_diagnosis_report
import new_diagnosis_report
import old_form_ambulance_usage_report
import new_form_ambulance_usage_report
import medical_card_history
import new_medical_card_history
import new_medical_card_report
import report1
import report2
import marketing_clinic_report
import print_gsc_data
1 个回答
这样的方法是最好的解决方案吗?或者说有没有更好的办法来解决这个问题呢?
不,这不是最好的方法!最好的方法是:
消除循环依赖。
真的。这意味着你的模块设计有问题。循环依赖本来就不应该存在。实际上,很多编程语言根本不允许出现这种情况。
你有几种方法可以解决这个问题:
- 调整这三个模块之间的定义,让每个模块不需要导入其他两个模块。
- 调整定义,使得导入只朝一个方向进行:比如说
b
导入a
,而c
导入a
和b
。 - 删除一个模块。你可能决定把一些本该放在一起的东西拆开了。例如,
c
可能并不需要,最好是不要拆分a
。 - 拆分某个模块(比如
c
),根据依赖关系将其定义分组。例如,c_a
将包含所有依赖于a
的c
的定义,而c_b
则包含所有依赖于b
的定义,并且c_a
和c_b
之间不相互导入。 - 彻底重写你正在做的设计。(循环依赖可能是更深层次问题的表现...)
如果出于某种原因,你确实想保留循环依赖,你可能可以通过把导致依赖的 import
放在文件的末尾来消除错误,而不是放在顶部。
不过,这并不总是可行,但如果你只在函数定义内部使用这个模块,这个方法应该有效。
另外,这样做会失去 import
的分组,这样你就不能简单地通过查看模块顶部来理解模块的依赖关系... 但如果导入在函数内部,这种情况会更糟,因为你还需要查看多个地方。