在 python 中,你知道如何正确地 import 模块吗?

1,462 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

在 python 我们见过多种方式导入一个 module,大家可能没有意识到他们之间区别,可能在认识上还存在 confusing,今天和大家一起来看一看这些写法不同 import 其背后又有什么区别。

如果对 python 如何导入一个 module 可以参考之前的一篇文章 在 python 中,在导入 module 背后究竟发生了什么?

import numpy as np
import torch
from tqdm import tqdm
import matplotlib.pyplot as plt

screenshot_002.png

首先我们会检测 sys.modules 中是否存在 socket 模块,如果已经加载就是定义 socket 对象指向存储 socket 对象的内存地址即可。如果 module 还没有加载,这需要对 module 文本进行编译执行来创建新的 module 对象,并且将 module 对象添加到 sys.modules 中。然后就是在全局命名空间内创建一个 symbol 或者变量指向创建好 module 对象内存地址。

在编译,还会将模块中包括方法、类等进行编译作为对象存储在内存中,在 socket 下的方法例如 gethostname 和 getnameinfo 都会被编译后存储在内存中,然后在 socket 持有这些引用的一个字典。

screenshot_003.png

也就是我们在 import module 时候其 module 中包含方法例如 gethostname 和 getnameinfo 这些方法也作为 object 保存到内存中,然后socket 持有一个字典,键值为方法或者类名称,值指向存储该 object 的内存地址。

import socket as my_socket

我们也可以为 socket 在导入时起一个别名,这样好处便于区分,或者对一些比较常用库进行进化例如,import numpy as np 这样方便随后调用 numpy 可以通过给其别名 np 来访问 numpy 模块。

screenshot_006.png

大家可能仅需要某一个 module 下的一个方法,然后通过如下语句导入 gethostname 方法。

from socket import gethostname

如果我们只想用 socket 的 gethostname 方法,这样做似乎节省了资源,直接加载使我们所需要 gethostname 方法,其实不然,即使这样做也会将 socket 整个对象及其下包含方法或者类也会事先加载到内存中,这样做和上面 import socket 开销是一样的,并没有节省内存。

from socket import *

这样做并不是什么明智选择,因为许多模块都存在相同名称的方法或者类,例如在 math 和 cmath 中就存在许多相同名称的方法或者类,我们利用别名方式来避免冲突。

from socket import gethostname as hostname