【问题标题】:Importing file from another imported file从另一个导入的文件导入文件
【发布时间】:2021-03-21 09:43:48
【问题描述】:

我的目录结构如下:

base_folder
    methods_folder
        method_1.py
        method_2.py
        .
        .
        .
        method_n.py
        class_methods.py
    top_class.py
    

class_methods.py 导入同一目录下的其他文件,如下所示:

from method_1 import method_1
from method_2 import method_2
.
.
.
from method_n import method_n

(obs:这些methods文件有一个方法,里面有自己的文件名)

如果我自己运行class_methods.py,没问题。但是如果我尝试运行导入class_methods.pytop_class.py,我会收到错误no module named method_1

所以,当执行top_class.py 时,它看不到methods_folder/ 中的文件。为什么?

【问题讨论】:

    标签: python relative-import


    【解决方案1】:

    top_class.py 中的正确导入将是 from methods_folder.method_n import method_n。这是因为您将methods_folder 视为一个包。如果您运行的是 3.3 之前的 Python 版本,您还必须在 methods_folder 中取消包含 __init__.py 文件才能将其转换为包。

    【讨论】:

      【解决方案2】:

      文件只能直接访问它们导入的内容。假设我们有 a.py 导入 b.pyb.py 导入 c.py。当在b.py 中使用c.pya.py 函数中运行时,这将正常工作,因为a 可以访问b,而b 可以访问c。然而,这并不意味着导入链(如在 C++ 中)和您可以在 a 中使用来自 c 的函数。你会得到一个错误,因为a 只能看到它导入的b 的内容。

      因此,如果您想使用 top_class.py 中的所有 method_i.py 文件,则需要将它们直接导入同一个文件中。

      编辑:您还有一些其他问题。要在子文件夹中导入其他文件,您需要在 top_class.py 中调用 import methods_folder.method_i。要在同一目录中导入某些内容,只需使用 import method_i。由于您在每个文件中都有一个同名的方法,因此您在class_methods.py 中工作正常您还需要在包含您打算导入/从中的python 文件的任何文件夹中创建一个名为__init__.py 的空文件,让python知道它可以看那里。

      【讨论】:

        【解决方案3】:

        您可以通过以下两种方式之一在 python 中创建可导入包。第一种方法是您正在做的事情:您创建一个名为my_package.py 的文件并使用import my_package 导入它。这通常用于不需要进一步分解的更简单的包。为此,您的 .py 文件必须位于 PYTHONPATH 上,这是一个环境变量,它告诉 python 在哪里查找包。如果未定义,python 将使用一些默认位置来查找包。其中一个默认位置是当前工作目录,这就是您的第一组导入工作的原因。

        理论上,您应该能够从同一位置 (python ../top_class.py) 运行第二段代码并使用相同的导入样式,但我假设您正在更改目录以运行该文件。这意味着您的文件不再位于当前工作目录中,并且不再被 python 找到。

        让您的代码使用现有样式运行的一种方法是使用您的 methodX.py 文件的位置定义PYTHONPATH。您通常会像这样添加到 python 搜索路径:

        PYTHONPATH=$PYTHONPATH:./methods_folder python top_class.py
        

        当你尝试导入某些东西时,这会告诉 python 在标准位置之外查找methods_folder。玩一会儿PYTHONPATH 会有点烦人,所以我实际上更喜欢下一种方法。

        创建包的第二种方法是创建一个文件夹,其中包含__init__.py 文件。这告诉 python 你希望它将该目录视为一个包。对于可能受益于跨多个文件的组织的更复杂的代码片段,这是首选样式。对于您的示例,您可以按以下方式组织代码:

        base_folder
            methods_folder
                __init__.py
                method_1.py
                method_2.py
                .
                .
                .
                method_n.py
                class_methods.py
            top_class.py
        

        然后您在 top_class.py 中的导入将如下所示:

        from methods_folder.method1 import method1
        from methods_folder.method2 import method2
        from methods_folder.method3 import method3
        

        这具有创建顶级methods_folder 包的效果,其中包含模块method1method2 等。因为methods_folder 与您正在运行top_class.py 的目录位于同一目录中,python 选择使用默认的 PYTHONPATH 将其作为一个包,并允许您从其中导入。

        【讨论】:

          【解决方案4】:

          我假设您是从它们各自的目录运行它们?除非它们安装在您的 Python 路径中(我假设它们不是),否则 Python 默认会在您的当前目录中查找导入。因此,当您从其目录运行 class_methods.py 时,它可以找到 methods_1.py 以满足from methods_1 import method_1。但是当你执行 top_class.py 时,它会查找 methods_1.pymethods_1/__init__.py,它们都不会从那个目录中被罚款。

          假设 Python 3,您需要在 class_methods.py 中使用相对导入。

          # class_methods.py
          from .methods_1 import method_1
          from .methods_2 import method_2
          

          这将让您从top_class.py 运行它。不幸的是,在同一个包中运行脚本时不能使用相对导入,因此不能直接运行class_methods.py

          在这种情况下,另一种选择是将绝对导入保留在 class_methods.py 中,并将方法文件夹添加到 top_class.py 中的路径中。

          import os 
          import sys
          
          sys.path.append(os.path.join(os.path.dirname(__file__), 'methods'))
          
          import class_methods
          from methods_1 import method
          

          当然,编辑 sys.path 对于小脚本和独立的东西是很好的。但是,如果这不再是一个脚本,那么您需要小心执行它,并且您可能只想想出另一个解决方案。可能,最好的办法是创建一个您安装的包(您仍然可以在开发时从源目录执行此操作),然后您可以从任何地方以相同的方式导入。

          【讨论】:

          • 好的,部分有效。我明白为什么要以这种方式使用相对导入以便top_class.py 阅读。但是,当我尝试自己运行class_methods.py 时,我得到了这个:No module named '__main__.check_duplicated_rec_entries'; '__main__' is not a package。为什么?这里发生了什么?
          • 对不起,误解了这个问题。没想到你还想跑class_methods.py。添加了一个更新来解决这个问题。
          【解决方案5】:

          运行 python 脚本的推荐方法是使用根包父级的-m 开关 - 所以在你的情况下:

          $ cd base_folder
          $ python -m top_class
          

          Python 会自动将 base_folder 添加到它的 sys.path 中,您不需要执行任何 sys.path/PYTHOPATH 黑客攻击,这些黑客攻击会用样板文件使代码膨胀,并且会在最意想不到的时候崩溃。

          现在运行class_methods的正确方法也是

          $ cd base_folder
          $ python -m methods_folder.class_methods
          

          但是class_methods 中的导入应该修改为绝对值:

          from methods_folder.method1 import method1
          ...
          

          或相对:

          from .method1 import method1
          ...
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-02-10
            • 2013-12-09
            • 2022-06-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-06-19
            相关资源
            最近更新 更多