从属性相互引用的类中循环导入

问题描述 投票:0回答:1

我知道有很多问题都在谈论循环导入。我看过很多,但我似乎无法弄清楚如何将它们应用到这个场景中。

我有一对数据加载类,用于从具有多个工作表的 Excel 文档导入数据。每个工作表都是可配置的,因此工作表名称和各个列名称可以更改(但它们在类属性中定义了默认值)。

所讨论的两个类之间还有其他类间引用,但我认为这个例子是最直接的:

单独导出脚本的功能之一是使用加载程序的元数据填充 Excel 模板(具有多个工作表)。该模板在每个工作表中引用其他工作表的列标题上都有注释,因为某些工作表的内容用于填充其他工作表中的下拉列表。

因此,一张工作表标题中的注释可能会显示“此列的下拉数据由工作表 2 中 X 列的内容填充”。并且工作表 2 的 X 列标题将有一条注释,内容为“此列的内容用于填充工作表 1 中 Y 列的下拉列表。”

我继续添加各自的导入,知道我最终会遇到循环导入问题,但我想我会在概念上建立关于我想要做的一切,然后尝试解决导入问题。

这里有一些玩具代码,可以尝试将其归结为:

infusates_loader.py

from DataRepo.loaders.tracers_loader import TracersLoader

class InfusatesLoader(TableLoader):
    DataColumnMetadata = DataTableHeaders(
        TRACERNAME=TableColumn.init_flat(
            ...
            source_sheet=TracersLoader.DataSheetName,
            source_column=TracersLoader.DataHeaders.NAME,
        ),
    )

tracers_loader.py

from DataRepo.loaders.infusates_loader import InfusatesLoader

class TracersLoader(TableLoader):
    DataColumnMetadata = DataTableHeaders(
        NAME=TableColumn.init_flat(
            ...
            # Cannot reference the InfusatesLoader here (to include the name of its
            # sheet and its tracer name column) due to circular import
            target_sheet=InfusatesLoader.DataSheetName,
            source_column=InfusatesLoader.DataHeaders.TRACERNAME,
        ),
    )

我现在可以通过在

tracers_loader.py
中设置静态字符串值来避免这个问题,但理想情况下,这些值只会存在于一个地方(每个值都在各自的类中)。

很多循环导入问题都与方法有关,所以我认为它们不适用于类属性?我尝试使用

importlib
并尝试在函数内进行导入,但是一旦它尝试设置类,我就会遇到导入错误。

python python-import circular-reference
1个回答
1
投票

循环导入问题的答案通常分为以下几类:

  • 避免错误并保持设计的技巧...
  • 您需要重新考虑您的重新设计

然而,“重新思考你的设计”通常不会伴随任何建议的设计模式。

显然,就我而言,这是一个设计问题。我知道情况很可能如此,但我只见树木不见森林。我坚持(正如 @user2357112 的评论所指出的)“单一事实来源”的概念。然而,我忽略了这样一个事实:我有一个与我正在建模的内容相符的概念选项。我的 Excel 文档中的每个工作表都有一个类,但我缺少文档本身的类,我可以在其中放置工作表间关系(以及文档中工作表列表的定义)。 @user2357112 将其称为“配置”,但我意识到这很容易成为一种“超类”或“协调类”。

我正要努力创建该类,但我确信这里需要一个定义表间关系的类。

我不知道如何称呼这样的设计模式,也不知道它会采取什么具体形式,但从概念上讲,这就是我所缺少的。

所以,举个例子,我需要的是这样的:

study_doc.py

class StudyDoc():
    infusates_tracer_reference: {
        "sheet": "Tracers",
        "column": "Name",
    }
    tracers_infusate_reference: {
        "sheet": "Infusates",
        "column": "Tracer Name",
    }

然后我可以将其导入到其他两个类中:

infusates_loader.py

from DataRepo.loaders.study_doc import StudyDoc

class InfusatesLoader(TableLoader):
    DataColumnMetadata = DataTableHeaders(
        TRACERNAME=TableColumn.init_flat(
            ...
            source_sheet=StudyDoc.infusates_tracer_reference["sheet"],
            source_column=StudyDoc.infusates_tracer_reference["column"],
        ),
    )

tracers_loader.py

from DataRepo.loaders.study_doc import StudyDoc

class TracersLoader(TableLoader):
    DataColumnMetadata = DataTableHeaders(
        NAME=TableColumn.init_flat(
            ...
            target_sheet=StudyDoc.tracers_infusate_reference["sheet"],
            source_column=StudyDoc.tracers_infusate_reference["column"],
        ),
    )

我可能会让它变得更复杂一些,但这是基本思想:所有这些关系都基于它们都属于同一个 Excel 文档的事实。该文档是关系的基础,因此它应该协调它们的连接。

© www.soinside.com 2019 - 2024. All rights reserved.