循环导入:包和模块之间的混淆

时间:2017-09-09 14:16:24

标签: python python-3.x import circular-dependency

这是我的包名为neuropredict(一堆模块和一个init文件;其中一个模块也称为neuropredict):

$ 09:50:24 miner neuropredict >>  tree setup.py neuropredict
setup.py [error opening dir]
neuropredict
├── config_neuropredict.py
├── freesurfer.py
├── __init__.py
├── __main__.py
├── model_comparison.py
├── neuropredict.py
├── rhst.py
├── test_rhst.py
├── visualize.py

0 directories, 16 files

repo在https://github.com/raamana/neuropredict处可用,包的init文件(其文件夹内容如上所示)是:

$ 09:50:27 miner neuropredict >>  cat neuropredict/__init__.py 

__all__ = ['neuropredict', 'rhst', 'visualize', 'freesurfer',
           'config_neuropredict', 'model_comparison']

from sys import version_info

if version_info.major==2 and version_info.minor==7:
    import neuropredict, config_neuropredict, rhst, visualize, freesurfer, model_comparison
elif version_info.major > 2:
    from neuropredict import neuropredict, config_neuropredict, rhst, visualize, freesurfer, model_comparison
else:
    raise NotImplementedError('neuropredict supports only 2.7 or Python 3+. Upgrade to Python 3+ is recommended.')

rhst.py中的导入代码(前20行)如下所示:

$ 09:50:40 miner neuropredict >>  head -n 20 neuropredict/rhst.py
from __future__ import print_function

__all__ = ['run', 'load_results', 'save_results']

if version_info.major==2 and version_info.minor==7:
    import config_neuropredict as cfg
elif version_info.major > 2:
    from neuropredict import config_neuropredict as cfg
else:
    raise NotImplementedError('neuropredict supports only 2.7 or Python 3+. Upgrade to Python 3+ is recommended.')

包中所有模块需要导入的配置文件包含一堆变量(没有任何if __name__ == __main__ code

$ 09:51:22 miner neuropredict >>  head -n 20 neuropredict/config_neuropredict.py
import matplotlib.pyplot as plt
NUM_TREES = 100
COMMON_FIG_SIZE = [9, 9]
CMAP_DATASETS = 'Paired'

对于Python 2.7,以下测试脚本可以工作(仅导入显示的部分代码)。但是,当我在Python 3.6下运行时,一切都会中断(某种循环导入舞蹈)。

$ 09:51:52 miner neuropredict >>  head -n 20 neuropredict/test_rhst.py 

import numpy as np
import os
import sys
from sys import version_info
from os.path import join as pjoin, exists as pexists, realpath

sys.dont_write_bytecode = True

from pyradigm import MLDataset

if version_info.major==2 and version_info.minor==7:
    from neuropredict import rhst
elif version_info.major > 2:
    from neuropredict.neuropredict import rhst
else:
    raise NotImplementedError('neuropredict supports only 2.7 or Python 3+. Upgrade to Python 3+ is recommended.')

从显示的错误中,我怀疑神经崩解(包)和神经预测(模块)之间的混淆是不应该发生在Python 3+中,因为它强烈建议仅使用显式导入。

另外,test_rhst.py在pytest下运行时不会报告任何错误,但只有当我在终端上使用python3.6 test_rhst.py运行时才会报错。

错误消息不是很有帮助(通常是can not import name rhstcan not import name config_neuropredict)而没有告诉我原因,例如ModuleNotFoundError。

此时,我正在考虑将模块重命名为与包名称neuropredict不同的模块,例如neupredict,或者压缩与python 2.7相关的所有代码,并且只在Python 3+中工作(我不确定是否会起作用)。

1 个答案:

答案 0 :(得分:1)

由于没有最小的工作示例,我无法正常测试,但如果我理解您的设置正确,我认为问题是您的test_rhst.py位于neuropredict/文件夹中;

test_rhst.py要求Python加载neuropredict时,Python会查看test_rhst.py的目录并找到您的neuropredict.py文件 - 它将找不到包含的内容。目录

因此,如果您要导入rhst.py,您应该import rhst ...除非您可能希望测试您的包的工作方式与最终用户使用它(您希望from neuropredict import rhst) 。为此,您应将测试文件放在包装外。

为什么from neuropredict import rhst有效?
因为neuropredict.py本身import rhst。所以from neuropredict import rhst通过rhst.py导入neuropredict.py,而不是通过neuropredict/包/目录。