Python - 导入包失败

3

我在导入包时遇到了问题。 我的文件结构如下:

filelib/  
    __init__.py
    converters/ 
        __init__.py
        cmp2locus.py
    modelmaker/ 
        __init__.py
        command_file.py

在模块command_file.py中,我有一个名为CommandFile的类,我想在cmp2locus.py模块中调用它。
我已经尝试了以下代码在cmp2locus.py模块中:
import filelib.modelmaker.command_file
import modelmaker.command_file
from filelib.modelmaker.command_file import CommandFile

所有这些选项都会返回ImportError: No modules named ...。 感激任何关于解决此问题的提示。我不明白为什么导入不起作用。

2个回答

5
为执行这些导入,您有三种选择,我将按我喜欢的顺序列出它们。(对于所有这些选项,我都将假设使用python 3)
相对导入
您的文件结构看起来像一个适当的包文件结构,因此这应该可以工作。但是,任何其他尝试此选项的人都应该注意,这要求您处于一个包中;这不适用于某些随机脚本。
您还需要从包外运行执行导入的脚本,例如通过导入并从那里运行它而不仅仅直接运行 cmp2locus.py 脚本。
然后,您需要使用 .. 将导入更改为相对导入。
import filelib.modelmaker.command_file

变成

from ..modelmaker import command_file
..指的是父文件夹(就像文件系统中的隐藏文件一样)。请注意,您必须使用from import语法,因为以..开头的名称在Python中不是有效的标识符。但是,您当然可以使用from import as将其导入为任何您想要的内容。
另请参见PEP

绝对导入

如果您将软件包放置在site-packages中(由site.getsitepackages()返回的目录),则可以使用您在问题中尝试使用的导入格式。请注意,这需要您软件包的任何用户也在那里安装它,因此这并不理想(尽管他们可能会这样做,依赖它是不好的)。

修改Python路径

正如Meera所回答的那样,您还可以直接使用sys修改Python路径。
个人不喜欢这个选项,因为它感觉非常“hacky”,但我被告知它可能很有用,因为它使您可以精确控制您可以导入什么。

谢谢@Blimmo。我喜欢相对导入的想法。实际上,我正在运行Python2.7。如果我尝试您的suggestion:from ..modelmaker import command_file,我会得到以下错误:ValueError: Attempted relative import in non-package。我需要在我的__initi__.py中添加任何特殊内容才能使其工作吗?还是Python2.7阻止了它? - duanerf
1
我刚才意识到了“而不只是运行cmp2locus.py”的评论。如果我想在这个特定的模块中使用它,我不确定应该从哪里导入它。 - duanerf
1
@duanerf你只需要在其他地方调用你想要导入的脚本,脚本仍然可以在其中使用导入。这是因为Python包并不真正意味着要运行它们自己,而是只是使用它们。所以你可以在包外面创建一个run.py文件,它只包括import filelib.converters.cmp2locus。这将从外部运行脚本,允许加载包。这个链接可能会有用。 - Blimmo

3

如果要从另一个文件夹导入,您需要将该文件夹的路径附加到sys.path中:

import sys
sys.path.append('path/filelib/modelmaker')
import command_file

谢谢@Meera。然而,似乎这并没有永久添加路径。这意味着我需要在我的代码中始终添加sys.path.append。我觉得这很奇怪,从未注意到这是必要的。有没有办法永久将我的filelib包添加到sys.path中,以便导入该库中的任何内容? - duanerf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接