你知道 Python 中导入模块时,幕后会发生什么

360影视 2025-01-30 16:38 2

摘要:在 Python 文件中使用import语句是非常常见的。即使对于经验丰富的 pythonista,导入也可能令人困惑,因为没有单一的方法可以保证导入始终有效。本文的目的是了解 import 语句工作原理的内部结构,以便更好地理解和解决常见的导入问题。在直接开

在 Python 文件中使用 import 语句是非常常见的。即使对于经验丰富的 pythonista,导入也可能令人困惑,因为没有单一的方法可以保证导入始终有效。本文的目的是了解 import 语句工作原理的内部结构,以便更好地理解和解决常见的导入问题。在直接开始之前,我们需要对 Python 模块有一定的了解,以了解 import 是如何工作的。

Python 模块是具有 .py 扩展名的文件。Python 模块的构建非常简单。我们需要做的就是创建一个 包含合法 Python 代码的文件,并为该文件命名.py扩展名。就是这样!!

模块是 Python 中促进代码模块化的构造。利用模块使我们能够在利用现有代码时使我们的程序更加健壮和强大。

例如,假设创建一个名为 mod.py 的模块,其中包含以下代码:

name = "Sarah"age = 26def greet: print("Welcome {}!!".format(name))class xyz: pass

可以通过导入模块来访问 mod.py 模块中的对象,如下所示:

>>> import mod>>> print(mod.name)Sarah>>> mod.age26>>> mod.greet'Welcome Sarah!!'>>> obj = mod.xyz>>> obj

当 Python 执行该语句时会发生什么:

import mod

当解释器执行上述 import 语句时,它会在从以下来源收集的目录列表中搜索 mod.py:

运行输入脚本的目录或当前目录(如果解释器以交互方式运行)。PYTHONPATH 环境变量中包含的目录列表(如果已设置)。(PYTHONPATH 的格式取决于 OS,但应模拟 PATH 环境变量.)在安装 Python 时配置的依赖于安装的目录列表。

生成的搜索路径可以在 Python 变量 sys.path 中访问,该变量是从名为 sys 的模块中获得的:

>>> import sys>>> sys.path['', '/home/roark/personal', '/home/roark/workdir','/usr/local/Python/3.7/lib','/usr/local/python3.7/site-packages','/usr/local/Python/3.7/python37.zip', '/usr/local/Python/3.7/lib/python3.7']

因此,为了确保找到我们的模块,我们需要执行以下操作之一:

将 mod.py 放在输入脚本所在的目录或当前工作目录(如果是交互式的)在启动解释器之前,修改 PYTHONPATH 环境变量以包含 mod.py 所在的目录(或将 mod.py 放在 PYTHONPATH 变量中已包含的目录之一中)

实际上还有一个额外的选项:我们可以将模块文件放在你选择的任何目录中,然后在运行时修改 sys.path,使其包含该目录。例如,在这种情况下,我们可以将 mod.py 放在目录 /home/sarah/ 中,然后发出以下语句:

>>> sys.path.append(r'/home/sarah/')>>> sys.path['', '/home/roark/personal', '/home/roark/workdir','/home/sarah','/usr/local/Python/3.7/lib','/usr/local/python3.7/site-packages','/usr/local/Python/3.7/python37.zip', '/usr/local/Python/3.7/lib/python3.7']>>> import mod

导入 module 后,我们可以使用 module 的 __file__ 属性确定找到它的位置:

>>> import mod>>> mod.__file__'/home/sarah/mod.py'>>> import datetime>>> datetime.__file__'/usr/local/Python/3.7/lib/datetime.py'

__file__ 的目录部分应该是 sys.path 中的目录之一。

最简单的形式就是我们在上面已经看到的那种。
进口

请注意,它不会使调用方直接访问模块内容。每个模块都有自己的私有符号表,该表用作模块中定义的所有目标文件的全局符号表。因此,如前所述,模块会创建一个单独的命名空间

从调用方,仅当通过点表示法以 为前缀时,才能访问模块中的对象,如下所示。

在以下 import 语句之后, mod 被放入本地符号表中。因此,mod 在调用者的本地上下文中具有意义:

>>> import modmod

语句 import 仅将 放在调用方的符号表中。在模块中定义的目标文件保留在模块的私有符号表中

因此, age, name, greet 和 xyz 保留在模块的私有符号表中,并且在调用方的上下文中没有意义。要在调用者的上下文中访问,模块中定义的对象名称必须以 mod 为前缀:

>>> greetNameError: name greet is not defined>>> mod.greet'Welcome Sarah!!'>>> mode.age26

An alternate form of the import statement allows individual objects from the module to be imported import 语句的另一种形式允许将模块中的各个对象直接导入到调用者的 symbol 表中。
from import

使用此语法,可以在调用方的环境中引用 ,而无需 前缀:

>>> from mod import name, greet>>> name'Sarah'>>> greet'Welcome Sarah!!'>>> from mod import xyz>>> obj = xyz>>> obj

由于这种形式的导入将对象名称直接放入调用方的 symbol 表中,因此已存在的任何同名对象都将被覆盖

>>> name = 'Roark'>>> age = 25>>> name, age('Roark', 25)>>> from mod import name, age>>> name, age('Sarah', 26)3. 从 导入 作为

也可以导入单个对象,但将它们输入到具有替代名称的本地符号表中。
from import as

这样就可以将名称直接放入本地符号表中,但避免与以前存在的名称发生冲突:

>>> name = 'Roark'>>> age = 25>>> from mod import name as k_name, age as k_age>>> name'Roark'>>> k_name'Sarah'>>> age25>>> k_age26

我们还可以用备用名称导入整个模块:
import as

>>> import mod as my_module>>> my_module.age26>>> my_module.greet'Welcome Sarah!!'

最后,带有 except ImportError 子句的 try 语句可用于防止不成功的导入尝试:

>>> try:... # Non-existent module... import def... except ImportError:... print('Module not found')...Module not found

来源:自由坦荡的湖泊AI

相关推荐