importerror_如何修复ModuleNotFoundError和ImportError

importerror

tl; dr (tl;dr)

  • Use absolute imports

    使用绝对导入

  • Append your project’s root directory to PYTHONPATH — In any environment you wish to run your Python application such as Docker, vagrant or your virtual environment i.e. in bin/activate, run (or e.g. add to bin/activate in case you are using virtualenv) the below command:

    将项目的根目录追加到 PYTHONPATH在任何要运行Docker,vagrant或虚拟环境等Python应用程序的环境中,即在bin / activate中运行(例如,如果使用virtualenv,则添加到bin/activate )中下面的命令:

export PYTHONPATH="${PYTHONPATH}:/path/to/your/project/"
  • *avoid using sys.path.append("/path/to/your/project/")

    *避免使用sys.path.append("/path/to/your/project/")

Module imports can certainly frustrate people and especially those who are fairly new to Python. Since I keep seeing relevant questions on StackOverflow on a daily basis, I decided to write an article here on Medium to try and describe how import works behind the scenes and what approach you need to follow in order to do your life easier.

模块的导入肯定会令人们感到沮丧,尤其是那些刚接触Python的人。 由于我每天都会在StackOverflow上看到相关的问题,因此我决定在Medium上写一篇文章,尝试描述导入在幕后的工作原理,以及为了简化生活而需要遵循的方法。

术语 (Terminology)

First, let’s start by defining some useful terms that will help you understand the concepts described in this article.

首先,让我们开始定义一些有用的术语,这些术语将帮助您理解本文中描述的概念。

  • A python module is a single file with a .py extension.

    python 模块是一个扩展名为.py的文件。

  • A python package is a folder that contains at least one python module. For python2, a package requires a __init__.py file

    python 软件包是一个文件夹,其中至少包含一个python模块。 对于python2,软件包需要__init__.py文件

  • A python package can contain any number of nested sub-packages, i.e. packages that contain other packages down the hierarchy of the project structure.

    python软件包可以包含任意数量的嵌套子软件包 ,即,在项目结构的层次结构中包含其他软件包的软件包。

  • imports are useful when a module needs to use some piece of functionality (e.g. a function or a class) written in another module (of the same or a different package or sub-package)

    当模块需要使用写在另一个模块(相同或不同的包或子包)中的某些功能(例如,函数或类)时, 导入非常有用

For example, consider the following project structure:

例如,考虑以下项目结构:

└── myproject
├── mypackage
│ ├── a.py
└── anotherpackage
├── b.py
├── c.py
└── mysubpackage
└── d.py

Project myproject contains two packages, mypackage and anotherpackage each of which contains a number of python modules, while the latter also contains a sub-package called mysubpackage which in turn contains an additional python module.

项目myproject包含两个包, mypackageanotherpackage其中的每一个包含许多Python模块,而后者还包含一个子包称为mysubpackage其又包含一个额外的Python模块。

模块导入如何在后台工作? (How does module import work behind the scenes?)

Now let’s assume that in your current module, you wish to import another module as shown below:

现在,假设您希望在当前模块中导入另一个模块,如下所示:

import a

Python will execute the above statement in two steps:

Python将分两步执行上述语句:

  • Locate, load and initialise (if required) the requested module

    找到,加载和初始化(如果需要)所请求的模块
  • Define necessary names in the local namespace and corresponding scope

    在本地名称空间和相应范围中定义必要的名称

Now Python interpreter is going to follow the next steps in an attempt to resolve a .

现在,Python解释器将要遵循试图解决的下一个步骤a

Step 1: sys.modules lookup

步骤1:sys.modules查找

Initially, Python will try to search for the module’s name insys.modules , which is a dictionary that maps module names to modules which have already been loaded. If the name is resolved successfully (which means that another module has already loaded it) will be then be made available to the local namespace otherwise, jump into step 2.

最初,Python将尝试在sys.modules搜索模块名称,这是一个字典,将模块名称映射到已加载的模块。 如果名称解析成功(这意味着已经加载了另一个模块),则该名称可用于本地名称空间,否则,请跳至步骤2。

Step 2: Python Standard Library lookup

步骤2:Python标准库查找

Python Standard Library contains built-in modules (written in C) that provide access to system functionality such as file I/O that would otherwise be inaccessible to Python programmers, as well as modules written in Python that provide standardized solutions for many problems that occur in everyday programming. Some of these modules are explicitly designed to encourage and enhance the portability of Python programs by abstracting away platform-specifics into platform-neutral APIs.

Python标准库包含内置模块(用C编写),这些模块提供对系统功能的访问,例如Python程序员无法访问的文件I / O,以及用Python编写的模块,它们为发生的许多问题提供标准化解决方案在日常编程中。 其中一些模块经过明确设计,旨在通过将特定于平台的内容抽象到与平台无关的API中来鼓励和增强Python程序的可移植性。

If the name couldn’t be found in sys.modules then Python is going to search for it in Python Standard Library. Again, if the name is resolved then it will be defined in the local namespace otherwise step 3 needs to be followed.

如果在sys.modules找不到该名称,则Python将在Python标准库中搜索该名称。 同样,如果名称被解析,那么它将在本地名称空间中定义,否则需要遵循步骤3。

Step 3: sys.path lookup

步骤3:sys.path查找

Now if the module’s name was not found either in sys.modules nor in standard library, Python will finally attempt to resolve it under sys.path. And this is the point where things can certainly go wrong. I believe most Python programmes are quite familiar with ModuleNotFoundError

现在,如果在sys.modules和标准库中都找不到模块的名称,Python将最终尝试在sys.path下解析它。 这是肯定会出错的地方。 我相信大多数Python程序对ModuleNotFoundError都很熟悉

import aModuleNotFoundError: No module named 'a'

or ImportError :

ImportError

from . import aImportError: cannot import name 'a'

绝对进口与相对进口 (Absolute vs Relative imports)

In absolute imports, we specify the explicit path starting from the project’s root directory. In our example

绝对导入中 ,我们指定从项目的根目录开始的显式路径。 在我们的例子中

└── myproject
├── mypackage
│ ├── a.py
└── anotherpackage
├── b.py
├── c.py
└── mysubpackage
└── d.py

this means that if we would like to import module a in module b we would have to specify

这意味着,如果我们想在模块b导入模块a ,则必须指定

import mypackage.a

Other valid examples are the following imports:

其他有效的示例是以下导入:

# in module a.py
import anotherpackage.mysubpackage.d# in module b
import anotherpackage.c

Now on the other hand, in relative imports we specify the path to the module relatively to the location of the current module. A few examples in our example could be:

现在,另一方面,在相对导入中,我们相对于当前模块的位置指定了模块的路径。 我们的示例中的一些示例可能是:

# in module a.py
from ..anotherpackage import b
from ..anotherpackage.b import another_function# in module b
from . import c
from .c import my_function

I’d personally discourage the use of relative imports as they are not as readable as absolute imports and PEP-8 suggests the same as well. In some rare cases, you might have to use relative imports in order to avoid unnecessarily long paths. For instance,

我个人不鼓励使用相对进口,因为相对进口的可读性不如绝对进口,PEP-8也建议这样做。 在极少数情况下,可能必须使用相对导入以避免不必要的长路径。 例如,

from package_a.sub_b.sub_c.sub_d.module_d import my_function

如何修复ModuleNotFoundError和ImportError? (How to fix ModuleNotFoundError and ImportError?)

Now we’re up to speed with how the basic import statement is executed and what is the difference between absolute and relative imports we can now go ahead and discuss what to do when your Python application fails with either ModuleNotFoundError or ImportError .

现在我们来了解基本import语句的执行方式以及绝对导入和相对导入之间的区别,我们现在可以继续讨论当Python应用程序出现ModuleNotFoundError失败时该怎么办。 要么 ImportError

In most of the cases, either of the errors occur due to the fact that Python is unable to resolve the module’s name in sys.path . Recall that when you call import a if the module’s name was found neither in sys.modules nor in standard library, Python will try to resolve it in sys.path . Likewise, when you use from syntax (e.g. from mypackage import a ), Python will first attempt to find and load the module. When it fails to do so, Python will throw ModuleNotFoundError for the first case or ImportError for the second case.

在大多数情况下,由于Python无法解析sys.path的模块名称,因此会发生两种错误。 回想一下,如果在sys.modules和标准库中都找不到模块名称时,调用import a时,Python将尝试在sys.path解析它。 同样,当您from语法中使用(例如from mypackage import a )时,Python将首先尝试查找并加载模块。 如果这样做失败,Python将在第一种情况下引发ModuleNotFoundError ,在第二种情况下引发ImportError

If that’s the case and recalling our example below,

如果是这样,请回想一下下面的示例,

└── myproject
├── mypackage
│ ├── a.py
└── anotherpackage
├── b.py
├── c.py
└── mysubpackage
└── d.py
  • first make sure you are using absolute imports

    首先确保您使用的是绝对导入

  • export the project’s root directory to PYTHONPATH

    将项目的根目录导出到 PYTHONPATH

Most modern Python IDEs will do the trick automatically but if this is not the case, I am pretty sure there will be such option where you’ll be able to define the PYTHONPATH for your Python application (at least PyCharm).

大多数现代Python IDE都会自动完成此操作,但如果不是这种情况,我很确定会有这样的选择,您可以为您的Python应用程序定义PYTHONPATH (至少是PyCharm)。

If you are running your Python application in any other environment such as Docker, Vagrant or inside your virutal environment you can run the below command in your bash:

如果您在Docker,Vagrant等任何其他环境中或在虚拟环境中运行Python应用程序,则可以在bash中运行以下命令:

export PYTHONPATH="${PYTHONPATH}:/path/to/your/project/"# * For Windows
set PYTHONPATH=%PYTHONPATH%;C:\path\to\your\project\

and now since your project’s root directory has been appended to PYTHONPATH your absolute imports should work like a charm.

现在,由于项目的根目录已附加到PYTHONPATH绝对导入应该像PYTHONPATH按钮一样工作。

sys.path.append(/path/to/your/project/ can possibly do the trick as well, but it’s definitely not a good practise.

sys.path.append(/path/to/your/project/也可以做到这一点,但这绝对不是一个好习惯。

结论 (Conclusion)

If you are new to Python, import modules can become a nightmare especially if you need to deal with a complex project structure. If you follow the two-step rule — i.e use absolute imports and append your project’s root directory to PYTHONPATH — then you shouldn’t really worry about module imports in the future.

如果您不熟悉Python,则导入模块可能会成为噩梦,尤其是在您需要处理复杂的项目结构时。 如果遵循两步法则(即使用绝对导入并将项目的根目录附加到PYTHONPATH),那么以后就不必担心模块导入了。

翻译自: https://towardsdatascience.com/how-to-fix-modulenotfounderror-and-importerror-248ce5b69b1c

importerror

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值