循环依赖 - 最好的方法?

时间:2014-06-18 07:21:01

标签: python python-import circular-dependency

我有两个三个文件:a.pyb.pyc.py

这三个文件位于不同的目录中(我们称之为a_dirb_dirc_dir)。 首先,我只有两个文件a.pyb.pyb.py有这个:

from root_dir.a_dir import a
...
do something
...

然后一切正常。但是当我创建第三个文件c.py时,我将其导入a.py,如下所示:

from root_dir.c_dir import c
...
do something
... 

我开始收到pyton无法将a导入b.py的错误。所以我认为它可能是循环依赖? 然后我改变了导入在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

P.S。此错误适用于我在问题b.py中命名的文件(当我在错误跟踪之前按照上面的说明更改a.py时)。

更新 目录的优先级导入:

import generic #c.py directory
import model #a.py directory
import report #b.py directory

UPDATE2

根据要求举例来重现问题(new_medical_card.pya.pymarketing_clinic_report.pyb.pygeneric.pyc.py):< / p>

模块文件和目录结构

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

根据要求 Update3 init导入:

我已经显示了主init文件(根目录中的那个 - ambulance_system,但为了清楚起见,原因也会在这里发布:

__init__.py 目录的优先级导入:

import generic #c.py directory
import model #a.py directory
import report #b.py directory

__init__.py表示通用目录(c.py):

import generic
对于模型目录(__init__.py

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报告目录(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 个答案:

答案 0 :(得分:3)

  

是最好的方法还是有更好的方法来解决这个问题   问题

不,这不是最好的方法!最好的方法是:

摆脱循环依赖

真。这只意味着您在这些模块中存在设计问题。首先不应存在循环依赖。事实上,很多编程语言都不允许它们出现。

您有多种选择:

  • 在三个模块中移动定义,以便每个模块不必导入另外两个模块。
  • 移动定义,以便导入仅“在一个方向”:例如b导入ac导入ab
  • 删除模块。你决定分开一些更好的东西来保持在一起。例如,c可能不是必需的,可能更好,以避免首先分割a
  • 拆分某些模块(例如c)以按依赖关系对其定义进行分组。例如,c_a将包含c a的所有定义,这些定义依赖于c_bb所有依赖c_a c_b的定义}和import 互相导入
  • 完全重写您正在做的设计。 (循环依赖可能是更深层次问题的症状......)

如果出于某种邪恶的原因,你确实希望保持循环依赖,那么可能通过放置导致import来消除错误>结束文件而不是顶部。

然而,这并不总是可行,但如果仅在函数定义中使用模块,它应该可以工作。

同样以这种方式你放松了{{1}} s的分组,这样你就不能简单地查看模块的顶部来理解模块的依赖性......但这甚至更糟当导入在函数内部时,因为在那种情况下你还必须查看多个地方