简体   繁体   English

为什么我必须在包的 __init__.py 中使用相对导入?

[英]Why do I have to use a relative import in a package's __init__.py?

Setup设置

test/
    main.py
    pkg/
        a.py
        __init__.py

main.py contains: main.py包含:

import pkg    
pkg.a

__init__.py contains: __init__.py包含:

from . import a

main.py can be run without errors. main.py可以正常运行。

Question问题

Changing the content of __init__.py to__init__.py的内容更改为

import a

gives the following error when running main.py :运行main.py时出现以下错误:

Traceback (most recent call last):
  File "C:/Users/me/PycharmProjects/test/main.py", line 1, in <module>
    import pkg
  File "C:\Users\me\PycharmProjects\test\pkg\__init__.py", line 1, in <module>
    import a
ModuleNotFoundError: No module named 'a'

Interestingly, __init__.py can be executed directly with python __init__.py without errors.有趣的是, __init__.py init__.py 可以直接用python __init__.py执行而不会出错。

What's going on?这是怎么回事?

When you run a python script, it's parent folder is added to sys.path当您运行 python 脚本时,它的父文件夹被添加到sys.path

  • run main.py: sys.path[0] = '../test'运行 main.py: sys.path[0] = '../test'
  • run init .py: sys.path[0] = '../test/pkg'运行init .py: sys.path[0] = '../test/pkg'

Your case: You try to "absolute-like" import a in __init__.py but the parent folder of a.py - which is '../test/pkg' - is not in the sys.path when you run main.py .您的情况:您尝试在__init__.py中“绝对类似” import a ,但是当您运行main.py时, a.py的父文件夹(即'../test/pkg' )不在 sys.path 中. This is why you get an error.这就是您收到错误的原因。 However, your absolute import is incomplete as it should always start at the top level folder, eg但是,您的绝对导入是不完整的,因为它应该始终从顶级文件夹开始,例如

from test.pkg import a

Final answer to your question: You don't have to use relative imports!您问题的最终答案:您不必使用相对进口!

See: PEP-8 : Absolute imports are recommended, as they are usually more readable and tend to be better behaved (or at least give better error messages) if the import system is incorrectly configured (such as when a directory inside a package ends up on sys.path).请参阅: PEP-8建议使用绝对导入,因为如果导入系统配置不正确(例如 package 中的目录结束时),它们通常更具可读性并且往往表现更好(或至少给出更好的错误消息)在 sys.path 上)。

And keep in mind that relative imports don't work in a top-level-script when __name__ = "__main__" , but from imported modules only.请记住,当__name__ = "__main__"时,相对导入在顶级脚本中不起作用,而只能从导入的模块中起作用。

You can learn more about absolute and relative imports here:您可以在此处了解有关绝对和相对导入的更多信息:
Absolute vs. explicit relative import of Python module Python 模块的绝对与显式相对导入
https://realpython.com/absolute-vs-relative-python-imports/ https://realpython.com/absolute-vs-relative-python-imports/

I suppose you are using Pycharm?我想你正在使用 Pycharm? Then that's one of the confusion cause.那么这就是混乱的原因之一。

For example, let's say your directory looks like this例如,假设您的目录如下所示

project1
    p1.py
    test/
        __init__.py
        main.py
        pkg/
            a.py
            __init__.py

If you run (F10) the main.py your default working directory will be project1/test , which does not contain the a.py so import a will not find anything.如果你运行 (F10) main.py你的默认工作目录将是project1/test ,它不包含a.py所以import a不会找到任何东西。

But if you run (F10) the pkg/__init__.py your working directory will be project1/test/pkg which has the a.py , and it works like what you tested.但是,如果您运行 (F10) pkg/__init__.py您的工作目录将是project1/test/pkg ,其中包含a.py ,它的工作方式与您测试的一样。

So in these situation, if you use from. import a所以在这些情况下,如果你使用from. import a from. import a it will look for the directory that file is, project1/test/pkg in this case, which will always work regardless your working directory. from. import a它将查找该文件所在的目录,在这种情况下为project1/test/pkg ,无论您的工作目录如何,它都将始终有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM