You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python项目包/模块结构依赖重复初始化问题求助

Python项目依赖初始化重复触发问题及结构优化求助

项目结构

Sitka
│   DataTickers.py
│   example.csv
│   FinDates.py
│   SitkaMongo.py
│   tickers_csv.csv
│   __init__.py
│
├───Fin
│   │   main.py
│   │   md_provider_control.py
│   │   Tofino.py
│   │   __init__.py
│   │
│   ├───Instruments
│   │   │   market_standard_instruments.py
│   │   └   __init__.py
│   │   
│   ├───Env
│   │   │   CurveClass.py
│   │
│   ├───Utils
│       │   charting.py
│       │   exchange_identifier_mapper.py
│       │   fin_mapper.py
│       │   md_provider_simulation.py
│       └   __init__.py

关键模块代码

Tofino.py

from .Env.CurveClass import CurveData as _CurveData

class Tofino():    
       
    def __init__(self, mdp, VAL_ENV = None):
        
        mdp.tofino = self  # link Tofino 
       
        # Public VE Refernce
        self.val_env = VAL_ENV
        self.ir_config = VAL_ENV.market

market_standard_instruments.py

# Standard Imports
import Sitka.FinDates as fdate 
import datetime as dt
import re
from itertools import product

# bunch of functions after this.

CurveClass.py

import pandas as pd
import datetime as dt
from dateutil.relativedelta import relativedelta

class CurveData():
    def __init__(self):
        self.do_stuff= self._stuff()

main.py

from Sitka.FinDates import getMainDates

# Sitka- Custom Imports
from .md_provider_control import MD_ProviderV3
from .Tofino import Tofino
import Sitka.Fin.Instruments.market_standard_instruments as mkt_std

def main() -> Tofino:
    #  < ---- do a bunch of stuff ---- >    

    return Tofino(mdp = mdp, VAL_ENV=ve.GLOBAL_VALN_ENV)

Sitka.Fin.init.py

import logging
import traceback

# Run Valuation Environment Startup
from .main import main

# Global Variables:
from .Tofino import Tofino  as _Tofino
 
tofino : _Tofino
tofino = None
try:    
    tofino = main()    # I was trying some stuff out here, hence the weird traceback in try
except:
    print(traceback.format_exc())    

问题描述

  1. 执行import Sitka.Fin as fin时,main.py中的import Sitka.Fin.Instruments.market_standard_instruments as mkt_std会在进入try块前再次触发Sitka.Fin.__init__流程,导致初始化运行2次。
  2. 仅为了IDE智能提示/自动补全添加子目录__init__.py,希望优化代码结构使其更简洁。
  3. 补充:在IPython控制台仅执行import Sitka.Fin.Instruments.market_standard_instruments as mkt_std,就会触发整个Sitka.Fin.__init__流程,不符合预期。

问题原因及解决方法

初始化重复触发的核心原因

Python导入模块时,若通过绝对导入引用子模块,会先加载父模块并执行其__init__.py。当前Sitka.Fin.__init__.py导入了main.py,而main.py又用绝对导入加载market_standard_instruments,混合使用绝对/相对导入可能导致模块被视为不同实例重复加载;同时__init__.py中直接执行业务初始化逻辑,只要父模块被触发加载就会执行该逻辑。

修复重复初始化

  1. 统一使用相对导入:将main.py中的绝对导入改为相对导入,避免触发父模块重复加载:

    # 替换main.py中的绝对导入
    from .Instruments import market_standard_instruments as mkt_std
    
  2. 剥离__init__.py中的业务逻辑:把初始化tofino的逻辑移到单独函数,让用户手动触发,而非导入时自动执行:

    # 修改后的Sitka.Fin.__init__.py
    import logging
    from .Tofino import Tofino as _Tofino
    
    tofino: _Tofino = None
    
    def init_tofino():
        global tofino
        from .main import main
        try:
            tofino = main()
        except Exception as e:
            import traceback
            print(traceback.format_exc())
    

    使用时需手动调用fin.init_tofino(),避免不必要的自动初始化。

  3. 规范Python路径:确保项目根目录(包含Sitka的目录)在sys.path中,可在启动脚本中添加:

    import sys
    from pathlib import Path
    sys.path.insert(0, str(Path(__file__).parent.parent))
    

代码结构优化

  1. 简化__init__.py职责:仅保留必要的导出声明,让__init__.py作为模块入口的导出层,不执行业务逻辑:

    # 优化后的Sitka.Fin.__init__.py
    from .Tofino import Tofino
    from .main import main
    from .Instruments.market_standard_instruments import *  # 按需导出常用内容
    
  2. 精简子模块__init__.py:对于Instruments、Utils等子目录,__init__.py可仅导出常用类/函数,或保留为空(Python 3.3+支持命名空间包,空文件不影响兼容性):

    # Sitka/Fin/Instruments/__init__.py
    from .market_standard_instruments import *
    

内容的提问来源于stack exchange,提问作者keynesiancross

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 09:20:42