ModuleNotFoundError: No module named 'sharedFunctions'

ModuleNotFoundError: No module named 'sharedFunctions'

我有一个 Python 项目,其中有以下文件夹结构:

> root
  > download_module
    > __init__.py
    > downloadProcess.py
    > sharedFunctions.py
    > someHelper.py
  > useSharedFunction.py

download_module/__init__.py有如下代码:

from .sharedFunctions import stringArgumentToDate
from .downloadProcess import downloadProcessMethod

sharedFunctions.py 文件包含以下函数:

def stringArgumentToDate(arg):
    dateformat = "%m/%d/%Y"
    date = None
    if arg.isnumeric():
        date = datetime.fromtimestamp(int(arg))
    if date == None:
        date = datetime.strptime(arg, dateformat)
    return date

然后在 useSharedFunction.py 我尝试导入共享函数并像这样使用它。

from download_module import stringArgumentToDate
from download_module import downloadProcessMethod

def main():
    arg = '03/14/2022'
    dateArg = stringArgumentToDate(arg)

if __name__ == '__main__':
    main()

当我尝试使用 python3 useSharedFunction.py 运行 时,出现以下错误:

Traceback (most recent call last):
File "useSharedFunction.py", line 4, in <module>
    from download_module import stringArgumentToDate
File "/Users/jacobo/Documents/project/download_module/__init__.py", line 2, in <module>
    from .download_module import downloadAndProcessMethod
File "/Users/jacobo/Documents/project/download_module/downloadProcess.py", line 10, in <module>
    from sharedFunctions import stringArgumentToDate, otherFunction
ModuleNotFoundError: No module named 'sharedFunctions'

我相信错误出在 downloadProcess 中,因为在文件的开头我们得到了这个导入:

from sharedFunctions import stringArgumentToDate, otherFunction
from someHelper import Helper

指的是兄弟文件。 但是我不确定什么是允许 运行 独立地 downloadProcess.py main 的正确修复,而且能够从根目录或模块外的任何其他文件调用它的方法之一.

考虑这个结构:

┬ module
|  ├ __init__.py
|  ├ importing_submodule.py
|  └ some_submodule.py
├ __main__.py
├ some_submodule.py
└ module_in_parent_dir.py

内容:

  • __main__.py

    import module
    
  • /module/__init__.py

    from . import importing_module
    
  • /module/importing_submodule.py

    from some_submodule import SomeClass
    
  • /module/some_submodule.py

    print("you imported from module")
    
    
    class SomeClass:
        pass
    
  • /some_submodule.py

    print("you imported from root")
    
    
    class SomeClass:
        pass
    
  • /module_in_parent_dir.py

    class SomeOtherClass:
        pass
    

同级导入的工作原理

(如果您已经知道,请跳过此部分)

现在让 运行 __main__.py 它会说 “你从 root 导入”.

但是如果我们稍微更改一下代码..

  • /module/importing_submodule.py
    from module.some_submodule import SomeClass
    

它现在说 “你从模块导入” 正如我们想要的,如果你没有配置,可能在 IDE 中有可怕的红线说“未解决的引用” IDE.

中的工作目录

这是如何发生的很简单:脚本根目录(当前工作目录)由主脚本决定(第一个脚本是 运行ning),python 使用命名空间。

Python的导入系统使用2种导入方式,为了方便起见,我们称其为绝对导入和相对导入。

  • 绝对导入:从sys.path和当前工作目录
  • 中列出的目录导入
  • 相对导入:相对于调用导入的脚本导入

而决定行为的是我们是否在模块名称的开头使用 .

由于我们是按from some_submodule导入的,没有进行点,所以python将其作为'Absolute import'(我们之前决定的术语)。

然后当我们还指定模块名称时 from module.some_submodule python 在路径列表或当前工作目录中查找 module

当然,这绝不是个好主意;脚本根目录可以通过 os.chdir() 之类的调用进行更改,然后模块文件夹中的子模块可能会丢失。

因此,同级导入的最佳做法是在模块文件夹内使用相对导入。

  • /module/importing_submodule.py
    from .some_submodule import SomeClass
    

制作双向工作的脚本

要在 运行ning 作为主脚本时导入它的兄弟模块,但在由其他脚本导入时仍作为子模块工作,然后使用 try - except 并查找 ImportError

importing_submodule.py为例:

  • /module/importing_submodule.py
    try:
        from .some_submodule import SomeClass
    except ImportError:
        # attempted relative import with no known parent package
        # because this is running as main script, there's no parent package.
        from some_submodule import SomeClass
    

从父目录导入模块有点棘手。

由于子模块现在是主脚本,相对导入到父级目录不起作用。

所以我们需要将父目录添加到sys.path,当脚本是运行ning作为主脚本时

  • /module/importing_submodule.py
    try:
        from .some_submodule import SomeClass
    except ImportError:
        # attempted relative import with no known parent package
        # because this is running as main script, there's no parent package.
        from some_submodule import SomeClass
    
        # now since we don't have parent package, we just append the path.
        from sys import path
        import pathlib
        path.append(pathlib.Path(__file__).parent.parent.as_posix())
    
        print("Importing module_in_parent_dir from sys.path")
    else:
        print("Importing module_in_parent_dir from working directory")
    
    # Now either case we have parent directory of `module_in_parent_dir`
    # in working dir or path, we can import it
    
    # might need to suppress false IDE warning this case.
    # noinspection PyUnresolvedReferences
    from module_in_parent_dir import SomeOtherClass
    

输出:

"C:\Program Files\Python310\python.exe" .../module/importing_module.py

you imported from module
Importing module_in_parent_dir from sys.path

Process finished with exit code 0
"C:\Program Files\Python310\python.exe" .../__main__.py

you imported from module
Importing module_in_parent_dir from working directory

Process finished with exit code 0