Python 如何知道从我正在处理的代码中导入,而不是从站点包中导入?

How does Python know to import from the code i'm working on, rather than importing from site-packages?

背景

我有一个正在处理的软件包,我也已将其安装到 site-packages。 (我使用 pip 安装了自己的包)

问题

Python 如何知道从“本地”代码(我正在处理的代码)导入,而不是从 site-packages 导入? 我问是因为 我想更好地理解并且我担心当我真的想使用我自己的(最新)代码时,我可能会以某种方式从 site-packages 导入代码

让我感到困惑的是,我们如何编写导入并不清楚。在我看来,程序员不知道她是在导入自己的代码还是从 site-packages 导入。我在这里遗漏了什么吗?


我曾想过使用相对导入,但据我所知,一般不推荐使用它们


我正在使用 Python 3.8.5

如果你想将你的包符号链接为开发安装,请使用:

pip install --no-dependencies --editable .

或:

python setup.py develop

无需修改sys.path

您当前的文件夹将被符号链接到站点包。因此,如果 你的包名是foo,你可以用

导入模块
from foo import bar
# or
import foo
foo.bar.do_something()

我会考虑创建一个 virtual enviroment 没有安装 pip 包。这是您可以确定您使用的是本地版本!

如果您对从哪里导入包感到困惑,可以使用 .__path__ 找出答案。

import my_package
print(my_pacakge.__path__)

Python的import机制(俗称进口机械)是基于Finders and Loaders的。当您使用 import 语句导入模块时,一系列查找器会尝试查找您正在导入的模块。您可以看到按以下顺序触发的所有查找器的列表:

>>> import sys
>>> sys.meta_path
[<class '_frozen_importlib.BuiltinImporter'>,
 <class '_frozen_importlib.FrozenImporter'>,
 <class '_frozen_importlib_external.PathFinder'>]

如果 none 的发现者能够解析模块,则 ModuleNotFoundError 被提出。

BuiltinImporter 解析预加载到解释器中的模块,如 sys、time、gc 等。 FrozenImporter 解决冻结模块。 PathFinder 通过 sys.path.

中的路径解析模块

正在打印 sys.path 显示您的当前目录是第一个条目,因此首先搜索匹配项。

这是一个简单的序列,您可以使用它来推断导入将从哪里发生:

  1. 是内置模块的模块部分。示例:import sys。即使你的当前目录中有一个名为 sys.py 的文件,由于 BuiltinImporter 首先被调用,它会解析内置的 sys 模块。
  2. 模块是否存在于您的当前目录中,因为这是 sys.path 中的第一个条目。
  3. 该模块是否作为核心 python 或站点包的一部分提供。

由 PathFinder 导入的模块(存在于 sys.path 中的模块)将具有 __path__ 作为属性,您可以检查它的位置。

也可以重新排序 sys.meta_path 中的查找器,甚至添加您自己的自定义查找器和加载器,让您完全控制和创造性地修改默认机器。可以注册自定义查找器和加载器以查找系统中其他地方的模块,甚至可以动态地从外部系统中查找。