【问题标题】:Importing files from different folder从不同文件夹导入文件
【发布时间】:2011-05-21 23:30:20
【问题描述】:

我有以下文件夹结构。

application
├── app
│   └── folder
│       └── file.py
└── app2
    └── some_folder
        └── some_file.py

我想从file.py 导入一些函数到some_file.py

我试过了

from application.app.folder.file import func_name

和其他一些尝试,但到目前为止我无法正确导入。我该怎么做?

【问题讨论】:

  • 阅读官方文档对我帮助很大! docs.python.org/3/reference/…
  • 如果子文件夹的名称中有破折号,它应该是下划线。例如 my-package ,里面有 my_app 文件夹和 tests 文件夹。如果 my_app 被命名为 my-app,你会遇到导入问题
  • applicationapp1app2foldersome_folder 都不是包,并且不包含 __init__.py,对吗?如果你要做很多这样的事情,是时候把它们做成一个包了。
  • 这取决于您是否将appapp2 理解为两个逻辑上独立的项目/包。如果它们是分开的(例如,app 是多个应用程序 app2app3、...的通用实用程序),那么您可以将 install the app from its Github repository 作为依赖项使用 app2 的(虚拟)环境pip 然后像使用任何其他第三方包一样使用它。

标签: python importerror python-import


【解决方案1】:

注意:此答案是针对一个非常具体的问题。对于大多数从搜索引擎来到这里的程序员来说,这不是您要寻找的答案。通常,您会将文件构建成包(请参阅其他答案),而不是修改搜索路径。


默认情况下,您不能。导入文件时,Python 只搜索入口点脚本运行所在的目录和sys.path,其中包括包安装目录等位置(实际上是a little more complex,但大多数情况下都是这样)。

但是,您可以在运行时添加到 Python 路径:

# some_file.py
import sys
# insert at 1, 0 is the script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file

【讨论】:

  • sys.path.append('/path/to/application/app/folder') 更干净 imo
  • @pseudosudo:是的,但是在开头插入它的好处是在命名冲突的情况下保证在其他路径(甚至是内置路径)之前搜索路径。跨度>
  • @kreativitea - sys.path 返回 list,而不是 deque,将 list 转换为 deque 并返回是很愚蠢的。
  • 它是否被认为是一种管理文件夹中 .py 文件的 Python 方式?我想知道...为什么默认情况下不支持它?将所有 .py 文件保存在一个目录中是没有意义的..
  • @Ofir:不,这不是一个干净的pythonic 解决方案。通常,您应该使用包(基于目录树)。此答案针对所提出的问题,并且由于某种原因继续获得大量支持。
【解决方案2】:

没有错:

from application.app.folder.file import func_name

只需确保folder 也包含__init__.py,这样就可以将其作为一个包包含在内。不知道为什么其他答案谈论PYTHONPATH

【讨论】:

  • 因为这不包括需要修改PYTHONPATH 的情况。假设您在同一级别上有两个文件夹:ABA 有一个 __init.py__。尝试从B 中的A 导入一些东西。
  • init.py__init__.py 文件中有什么内容?
  • @Xinyang 可以是空文件。它的存在告诉 Python 将目录视为一个包。
  • 这不是目前投票率最高的答案,但它是最正确的答案(对于大多数情况)。只需创建一个包。这并不难。需要其他答案,因为有时您可能会受到某些系统更改(创建或修改文件等)的限制,例如在测试期间。
  • 无论我尝试什么,这都行不通。我想从“兄弟”目录导入,所以一个上一个下。都有 __ init __.py,包括父级。这是 python 3 特有的吗?
【解决方案3】:

当模块位于并行位置时,如问题:

application/app2/some_folder/some_file.py
application/app2/another_folder/another_file.py

这个速记使一个模块对另一个模块可见:

import sys
sys.path.append('../')

【讨论】:

  • 作为一个警告:只要导入脚本从其包含目录运行,它就可以工作。否则,运行脚本的任何其他目录的父目录都将附加到路径中,并且导入将失败。
  • 为了避免这种情况,我们可以获取文件sys.path.append(os.path.dirname(os.path.abspath(__file__)))的父目录
  • 这对我不起作用 - 我必须在其中添加一个额外的目录名才能爬回父级,以便从命令行运行 cli/foo.py 能够import cli.bar
  • @Rahul,您的解决方案不适用于交互式外壳
  • 如果您从根文件夹(即应用程序文件夹)运行它,您可能对sys.path.append('.') 没问题,然后使用from app2.some_folder.some_file import your_function 导入模块。或者,对我有用的是从根文件夹运行python3 -m app2.another_folder.another_file
【解决方案4】:

首先在name-file.py中导入sys

 import sys

第二在name-file.py中追加文件夹路径

sys.path.insert(0, '/the/folder/path/name-package/')

第三在您的子目录中创建一个名为 __ init __.py 的空白文件(这告诉 Python 它是一个包)

  • name-file.py
  • 名称包
    • __ 初始化 __.py
    • name-module.py

第四在name-file.py文件夹内导入模块

from name-package import name-module

【讨论】:

  • 由于 name-folder 位于 name-file.py 的正下方,即使没有 sys.path.insert-command,这也应该可以工作。因此,答案留下了问题,即使名称文件夹位于任意位置,此解决方案是否也有效。
  • 你是说我必须硬编码脚本的路径吗?这意味着该解决方案不可移植。另外问题是如何从一个子文件夹访问另一个子文件夹。为什么不遵循原始问题的名称约定和文件结构?
  • @Giacomo 你不必硬编码任何东西。只需将其作为参数传递给脚本即可。
【解决方案5】:

我认为一种特别的方式是使用the environment variable PYTHONPATH,如文档中所述:Python2Python3

# Linux & OSX
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

# Windows
set PYTHONPATH=C:\path\to\dirWithScripts\;%PYTHONPATH%

【讨论】:

  • 等等,我可以用文件名替换 myScripts 吗?
  • 否,使用 .py 文件的目录路径
  • 不幸的是,如果您使用的是 Anaconda,这将不起作用,因为在内部并没有真正使用 PYTHONPATH!
  • 对于 anaconda 中的(最近)更改,请参阅此 SO 以了解工作流和 cmets 以了解变通方法:stackoverflow.com/questions/17386880/… 一般来说,构建和安装小包而不是破解导入目录。
【解决方案6】:

您的问题是 Python 正在 Python 目录中查找此文件,但没有找到它。您必须指定您正在谈论的是您所在的目录,而不是 Python 目录。

要做到这一点,你改变这个:

from application.app.folder.file import func_name

到这里:

from .application.app.folder.file import func_name

通过添加点,您要在此文件夹中查找应用程序文件夹,而不是在 Python 目录中查找。

【讨论】:

  • ImportError: 尝试在没有已知父包的情况下进行相对导入 :(
  • 我遇到了同样的错误,有什么解决办法吗?
【解决方案7】:

这里的答案不够清晰,这是在 Python 3.6 上测试的

使用此文件夹结构:

main.py
|
---- myfolder/myfile.py

myfile.py 的内容在哪里:

def myfunc():
    print('hello')

main.py中的import语句为:

from myfolder.myfile import myfunc
myfunc()

这将打印 hello

【讨论】:

  • 在我的文件夹中添加一个 init.py(空)配置文件在 linux (y) 上对我有用
  • @Vincent 你的意思是__init__.py
  • 由于某种原因添加__init__.py 对我不起作用。我在 Ubuntu 18 上使用 Py 3.6.5。它适用于 Pycharm,但不能从终端
  • 这与询问从文件树的不同分支而不是当前工作目录导入文件的问题完全无关。
  • 可爱的图表明确忽略了 OP 的问题。
【解决方案8】:

在 Python 3.4 及更高版本中,您可以import from a source file directly (link to documentation)。这不是最简单的解决方案,但为了完整起见,我将这个答案包括在内。

这是一个例子。一、要导入的文件,命名为foo.py

def announce():
    print("Imported!")

导入上述文件的代码很大程度上受到文档中示例的启发:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

foo = module_from_file("foo", "/path/to/foo.py")

if __name__ == "__main__":
    print(foo)
    print(dir(foo))
    foo.announce()

输出:

<module 'foo' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

请注意,变量名、模块名和文件名不必匹配。此代码仍然有效:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

baz = module_from_file("bar", "/path/to/foo.py")

if __name__ == "__main__":
    print(baz)
    print(dir(baz))
    baz.announce()

输出:

<module 'bar' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

以编程方式导入模块是在 Python 3.1 中引入的,让您可以更好地控制模块的导入方式。有关详细信息,请参阅文档。

【讨论】:

  • 我不知道是否有人试图理解这一点,但我认为它太复杂了。
  • 这是唯一对我有用的解决方案。我在不同的目录中有相同的文件名。
  • 如何导入文件中的所有内容?
【解决方案9】:

据我所知,直接在要导入的函数的文件夹中添加一个__init__.py 文件即可。

【讨论】:

  • 仅当想要包含该其他目录的脚本已经在 sys.path 中时
  • 我在 Windows 上使用了sys.path.append(tools_dir),不需要添加__init__.py' file in my directory tools_dir`
【解决方案10】:

尝试 Python 的相对导入:

from ...app.folder.file import func_name

每个前导点都是从当前目录开始的层次结构中的另一个更高级别。


问题?如果这对您不起作用,那么您可能会被许多 gotcha 的相对导入所吸引。 阅读答案和 cmets 了解更多详情: How to fix "Attempted relative import in non-package" even with __init__.py

提示:在每个目录级别都有__init__.py。您可能需要从顶级目录运行的python -m application.app2.some_folder.some_file(不包括 .py),或者在 PYTHONPATH 中拥有该顶级目录。 呼!

【讨论】:

  • 如果您的目录名称以数字开头(例如,import ..70_foo.test 不允许),这似乎不起作用
  • 哇,这确实有效。我不知道你可以通过使用多个点来“向上”一个目录。
【解决方案11】:

将应用程序移动到其他环境时,将sys.path.append 与绝对路径一起使用并不理想。使用相对路径并不总是有效,因为当前工作目录取决于脚本的调用方式。

由于应用程序文件夹结构是固定的,我们可以使用os.path 来获取我们希望导入的模块的完整路径。例如,如果这是结构:

/home/me/application/app2/some_folder/vanilla.py
/home/me/application/app2/another_folder/mango.py

假设您要导入 mango 模块。您可以在 vanilla.py 中执行以下操作:

import sys, os.path
mango_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ '/another_folder/')
sys.path.append(mango_dir)
import mango

当然,您不需要 mango_dir 变量。

要了解其工作原理,请查看此交互式会话示例:

>>> import os
>>> mydir = '/home/me/application/app2/some_folder'
>>> newdir = os.path.abspath(os.path.join(mydir, '..'))
>>> newdir
    '/home/me/application/app2'
>>> newdir = os.path.abspath(os.path.join(mydir, '..')) + '/another_folder'
>>> 
>>> newdir
'/home/me/application/app2/another_folder'
>>> 

并查看os.path 文档。

另外值得注意的是,使用packages 时处理多个文件夹更容易,因为可以使用带点的模块名称。

【讨论】:

    【解决方案12】:

    我也面临同样的挑战,尤其是在导入多个文件时,我设法克服了它。

    import os, sys
    
    from os.path import dirname, join, abspath
    sys.path.insert(0, abspath(join(dirname(__file__), '..')))
    
    from root_folder import file_name
    

    【讨论】:

    • 如果您能解释一下它与普通导入有何不同,您的回答会更有帮助?
    • 我有 /path/dir1/__init__.py 和 /path/dir1/mod.py。对于 /path/some.py from dir1.mod import func 有效。在 /path/dir2/some.py 中,它仅在我将上述答案复制并粘贴到文件顶部后才起作用。不想编辑我的路径,因为不是我拥有的每个 python 项目都在 /path/ 中。
    • 我的测试文件在添加此导入后使用bazel 运行时被移动到另一个目录,测试文件能够引用依赖项。
    【解决方案13】:

    在 linux 上的 python3 中为我工作

    import sys  
    sys.path.append(pathToFolderContainingScripts)  
    from scriptName import functionName #scriptName without .py extension  
    

    【讨论】:

    • sys.path.append("/home/linux/folder/") — 确保不要使用快捷方式,例如"~/folder/"
    • 这是最简单的答案;也适用于 Windows。
    【解决方案14】:

    application 视为您的python 项目的根目录,在applicationappfolder 文件夹中创建一个空的__init__.py 文件。然后在您的some_file.py 中进行如下更改以获得func_name 的定义:

    import sys
    sys.path.insert(0, r'/from/root/directory/application')
    
    from application.app.folder.file import func_name ## You can also use '*' wildcard to import all the functions in file.py file.
    func_name()
    

    【讨论】:

    • 应该是:sys.path.insert(0, r'/from/root/directory')
    【解决方案15】:

    创建包的最佳实践是从最高级别目录中的main_module.py 等模块运行和访问其他模块。

    这个结构展示了你可以通过顶级目录文件main_module.py来使用和访问子包、父包或同级包和模块。

    创建并运行这些文件和文件夹以进行测试:

     package/
        |
        |----- __init__.py (Empty file)
        |------- main_module.py (Contains: import subpackage_1.module_1)        
        |------- module_0.py (Contains: print('module_0 at parent directory, is imported'))
        |           
        |
        |------- subpackage_1/
        |           |
        |           |----- __init__.py (Empty file)
        |           |----- module_1.py (Contains: print('importing other modules from module_1...')
        |           |                             import module_0
        |           |                             import subpackage_2.module_2
        |           |                             import subpackage_1.sub_subpackage_3.module_3)
        |           |----- photo.png
        |           |
        |           |
        |           |----- sub_subpackage_3/
        |                        |
        |                        |----- __init__.py (Empty file)
        |                        |----- module_3.py (Contains: print('module_3 at sub directory, is imported')) 
        |
        |------- subpackage_2/
        |           |
        |           |----- __init__.py (Empty file)
        |           |----- module_2.py (Contains: print('module_2 at same level directory, is imported'))
    

    现在运行main_module.py

    输出是

    >>>'importing other modules from module_1...'
       'module_0 at parent directory, is imported'
       'module_2 at same level directory, is imported'
       'module_3 at sub directory, is imported'
    

    打开图片和文件注意:

    在包结构中,如果要访问照片,请使用最高级别目录中的绝对目录。

    假设您正在运行main_module.py,并且您想在module_1.py 中打开photo.png

    module_1.py 必须包含的是:

    正确:

    image_path = 'subpackage_1/photo.png'
    cv2.imread(image_path)
    

    错误:

    image_path = 'photo.png'
    cv2.imread(image_path)
    

    虽然module_1.pyphoto.png 在同一个目录下。

    【讨论】:

      【解决方案16】:

      这适用于我在 Windows 上

      # some_file.py on mainApp/app2 
      import sys
      sys.path.insert(0, sys.path[0]+'\\app2')
      
      import some_file
      

      【讨论】:

        【解决方案17】:

        就我而言,我有一个要导入的类。我的文件如下所示:

        # /opt/path/to/code/log_helper.py
        class LogHelper:
            # stuff here
        

        在我的主文件中,我通过以下方式包含了代码:

        import sys
        sys.path.append("/opt/path/to/code/")
        from log_helper import LogHelper
        

        【讨论】:

        • @not2qubit sys 未在答案中导入。
        【解决方案18】:
        ├───root
        │   ├───dir_a
        │   │   ├───file_a.py
        │   │   └───file_xx.py
        │   ├───dir_b
        │   │   ├───file_b.py
        │   │   └───file_yy.py
        │   ├───dir_c
        │   └───dir_n
        

        您可以将父目录添加到PYTHONPATH,为此,您可以使用sys.path 中列出的“模块搜索路径”中的操作系统依赖路径。因此,您可以轻松添加父目录,如下所示:

        # file_b.py
        
        import sys
        sys.path.insert(0, '..')
        
        from dir_a.file_a import func_name
        

        【讨论】:

          【解决方案19】:

          我多次遇到同样的问题,所以我想分享我的解决方案。

          Python 版本:3.X

          以下解决方案适用于使用 Python 3.X 版开发您的应用程序的人,因为Python 2 is not supported since Jan/1/2020

          项目结构

          在 python 3 中,由于Implicit Namespace Packages,您的项目子目录中不需要__init__.py。见Is init.py not required for packages in Python 3.3+

          Project 
          ├── main.py
          ├── .gitignore
          |
          ├── a
          |   └── file_a.py
          |
          └── b
              └── file_b.py
          

          问题陈述

          file_b.py,我想在文件夹a下的file_a.py中导入一个类A

          解决方案

          #1 一种快速但肮脏的方式

          无需像您当前正在开发新项目那样安装软件包

          使用try catch 检查是否有错误。代码示例:

          import sys
          try:
              # The insertion index should be 1 because index 0 is this file
              sys.path.insert(1, '/absolute/path/to/folder/a')  # the type of path is string
              # because the system path already have the absolute path to folder a
              # so it can recognize file_a.py while searching 
              from file_a import A
          except (ModuleNotFoundError, ImportError) as e:
              print("{} fileure".format(type(e)))
          else:
              print("Import succeeded")
          

          #2 安装你的包

          一旦你安装了你的应用程序(在这篇文章中,安装教程不包括在内)

          你可以简单

          try:
              from __future__ import absolute_import
              # now it can reach class A of file_a.py in folder a 
              # by relative import
              from ..a.file_a import A  
          except (ModuleNotFoundError, ImportError) as e:
              print("{} fileure".format(type(e)))
          else:
              print("Import succeeded")
          

          编码愉快!

          【讨论】:

          • 关于absolute imports的更多信息
          • 您提出的第一个解决方案使用 sys.path.insert(1, '../a/') 对我有用,我认为这比编写完整路径更好。
          • 如果有人想要导入本地包而不是系统包(具有相同名称),请使用 sys.path.insert(1,'folder-to-grab- package-from') 而不是 sys.append('folder-to-grab-package-from')
          【解决方案20】:

          我很特别:我在 Windows 上使用 Python!

          我只是完成信息:对于 Windows 和 Linux,相对路径和绝对路径都适用于 sys.path(我需要相对路径,因为我在多台 PC 和不同的主目录下使用我的脚本)。

          在使用 Windows 时,\/ 都可以用作文件名的分隔符,当然您必须将 \ 加倍到 Python 字符串中,
          一些有效的例子:

          sys.path.append('c:\\tools\\mydir')
          sys.path.append('..\\mytools')
          sys.path.append('c:/tools/mydir')
          sys.path.append('../mytools')
          

          (注意:我认为/\ 更方便,如果它不是“Windows-native”,因为它与 Linux 兼容并且更易于编写和复制到 Windows 资源管理器)

          【讨论】:

          • os.path.join('tools', 'mydir')
          【解决方案21】:

          如果从特定路径加载模块的目的是在开发自定义模块期间为您提供帮助,您可以在测试脚本的同一文件夹中创建一个指向自定义模块根目录的符号链接。对于在该文件夹中运行的任何脚本,此模块引用将优先于安装的任何其他同名模块。

          我在 Linux 上对此进行了测试,但它应该适用于任何支持符号链接的现代操作系统。

          这种方法的一个优点是您可以指向位于您自己的本地 SVC 分支工作副本中的模块,这可以大大简化开发周期时间并减少管理模块不同版本的故障模式。

          【讨论】:

            【解决方案22】:

            不要只是做import ...,而是这样做:

            from &lt;MySubFolder&gt; import &lt;MyFile&gt;

            MyFile 在 MySubFolder 中。

            【讨论】:

              【解决方案23】:

              我正在处理项目 a,我希望用户通过 pip install a 使用以下文件列表进行安装:

              .
              ├── setup.py
              ├── MANIFEST.in
              └── a
                  ├── __init__.py
                  ├── a.py
                  └── b
                      ├── __init__.py
                      └── b.py
              

              setup.py

              from setuptools import setup
              
              setup (
                name='a',
                version='0.0.1',
                packages=['a'],
                package_data={
                  'a': ['b/*'],
                },
              )
              

              MANIFEST.in

              recursive-include b *.*
              

              a/init.py

              from __future__ import absolute_import
              
              from a.a import cats
              import a.b
              

              a/a.py

              cats = 0
              

              a/b/init.py

              from __future__ import absolute_import
              
              from a.b.b import dogs
              

              a/b/b.py

              dogs = 1
              

              我通过在MANIFEST.in 的目录中运行以下命令来安装模块:

              python setup.py install
              

              然后,从我的文件系统 /moustache/armwrestle 上一个完全不同的位置,我能够运行:

              import a
              dir(a)
              

              这证实了 a.cats 确实等于 0 和 a.b.dogs 确实等于 1,正如预期的那样。

              【讨论】:

                【解决方案24】:

                我通常会为要导入的模块创建一个符号链接。符号链接确保 Python 解释器可以在当前目录中找到模块(您将另一个模块导入到的脚本);稍后当您的工作结束时,您可以删除符号链接。此外,您应该忽略 .gitignore 中的符号链接,这样您就不会意外地将符号链接模块提交到您的存储库。这种方法甚至可以让您成功使用与您正在执行的脚本平行的模块。

                ln -s ~/path/to/original/module/my_module ~/symlink/inside/the/destination/directory/my_module
                

                【讨论】:

                  【解决方案25】:

                  万一有人还在寻找解决方案。这对我有用。

                  Python 会将包含您启动的脚本的文件夹添加到 PYTHONPATH,因此如果您运行

                  python application/app2/some_folder/some_file.py
                  

                  只有文件夹 application/app2/some_folder 被添加到路径中(不是您在其中执行命令的基本目录)。相反,将文件作为模块运行并在 some_folder 目录中添加 __init__.py。

                  python -m application.app2.some_folder.some_file
                  

                  这会将基本目录添加到 python 路径,然后可以通过非相对导入访问类。

                  【讨论】:

                    【解决方案26】:

                    所以我刚刚右键单击了我的 IDE,并添加了一个新的 folder,我想知道为什么我无法从中导入。后来我意识到我必须右键单击并创建一个 Python 包,而不是一个经典的文件系统文件夹。或者如其他答案中所述,添加__init__.py(这使得python将文件系统文件夹视为一个包)的事后分析方法。在这里添加这个答案,以防有人走这条路。

                    【讨论】:

                      【解决方案27】:

                      您可以使用 importlib 将模块导入您想要从文件夹中导入模块的位置,使用如下字符串:

                      import importlib
                      
                      scriptName = 'Snake'
                      
                      script = importlib.import_module('Scripts\\.%s' % scriptName)
                      

                      这个例子有一个 main.py,它是上面的代码,然后是一个名为 Scripts 的文件夹,然后你可以通过更改 scriptName 变量从这个文件夹中调用你需要的任何东西。然后你可以使用script 来引用这个模块。例如,如果我在 Snake 模块中有一个名为 Hello() 的函数,您可以通过这样做来运行此函数:

                      script.Hello()
                      

                      我已经在 Python 3.6 中对此进行了测试

                      【讨论】:

                        【解决方案28】:

                        我曾多次遇到这些问题。我经常来这个页面。 在我的最后一个问题中,我必须从固定目录运行server,但每当调试时我想从不同的子目录运行。

                        import sys
                        sys.insert(1, /path) 
                        

                        对我有用吗,因为在不同的模块中我必须读取不同的 *.csv 文件,这些文件都在同一个目录中。

                        最后,我猜对我有用的不是pythonic,而是:

                        我在我要调试的模块上使用了if __main__ ,它从不同于通常的路径运行。

                        所以:

                        # On top of the module, instead of on the bottom
                        import os
                        if __name__ == '__main__':
                            os.chdir('/path/for/the/regularly/run/directory')
                        

                        【讨论】:

                          【解决方案29】:

                          如果您有多个文件夹和子文件夹,您可以随时从主目录导入任何类或模块。

                          例如:项目的树形结构

                          Project 
                          ├── main.py
                          ├── .gitignore
                          |
                          ├── src
                               ├────model
                               |    └── user_model.py
                               |────controller
                                    └── user_controller.py
                          

                          现在,如果您想从 ma​​in.py 文件中的 user_model.py 导入 "UserModel" 类,您可以使用:

                          from src.model.user_model.py import UserModel
                          

                          此外,您可以使用同一行在 user_controller.py 文件中导入相同的类:

                          from src.model.user_model.py import UserModel
                          

                          总的来说,您可以参考主项目目录来导入Project目录内任何python文件中的类和文件。

                          【讨论】:

                          • 我们是否需要 src 下的 __init__.py 来实现这一点?
                          • 这不是对原始问题的回答,这不是关于如何从 main.py 导入,而是(按照您的示例)从 user_model.py 到 user_controller.py。
                          【解决方案30】:

                          以下代码以 Python 版本安全的方式导入由其路径给出的 Python 脚本,无论它位于何处:

                          def import_module_by_path(path):
                              name = os.path.splitext(os.path.basename(path))[0]
                              if sys.version_info[0] == 2:   
                                  # Python 2
                                  import imp
                                  return imp.load_source(name, path)
                              elif sys.version_info[:2] <= (3, 4):  
                                  # Python 3, version <= 3.4
                                  from importlib.machinery import SourceFileLoader
                                  return SourceFileLoader(name, path).load_module()
                              else:                            
                                  # Python 3, after 3.4
                                  import importlib.util
                                  spec = importlib.util.spec_from_file_location(name, path)
                                  mod = importlib.util.module_from_spec(spec)
                                  spec.loader.exec_module(mod)
                                  return mod
                          

                          我在 psutils.test.__init__.py 的第 1042 行 psutils 的代码库中找到了这个(最近一次提交到 09.10.2020)。

                          使用示例:

                          script = "/home/username/Documents/some_script.py"
                          some_module = import_module_by_path(script)
                          print(some_module.foo())
                          

                          重要提示:该模块将被视为顶级;从其中的父包中进行的任何相对导入都将失败。

                          【讨论】:

                          • 知道为什么有两种不同的 Python3 方法吗?我在 Python 3.6 上都试过了,它们都可以工作,并返回相同的结果
                          • 在 python 3.8.9 上的结果也相同。从 3.8.10 及更高版本开始,spec_from_file_location 开始在 loader 对象中保存文件的根路径(如果给定了相对路径),否则返回的数据相同。还使用 python 3.10 进行了测试——与 3.8.10 完全相同的行为。两种方法都可以正常工作。
                          • @Jon 不幸的是我不能评论这些,我不熟悉 importlib 的细微差别。这是找到的财产​​,我不想改变任何东西 - 认为他们有理由这样做。也许有一些不同的细微差别,或者旧/新版本的差异。
                          猜你喜欢
                          • 1970-01-01
                          • 2022-11-16
                          • 1970-01-01
                          • 1970-01-01
                          • 2018-07-19
                          • 2018-08-19
                          相关资源
                          最近更新 更多