当前位置:首页>python>【一起学 Python】第 32 天:模块的导入:import 与 from...import

【一起学 Python】第 32 天:模块的导入:import 与 from...import

  • 2026-08-22 19:30:56
【一起学 Python】第 32 天:模块的导入:import 与 from...import
昨天我们完成了函数式编程的最后一块拼图 reduce()。今天,我们要回归工程化基础,深入探讨 模块的导入机制。
虽然我们在之前的课程中经常使用 import,但你是否清楚 import module 和 from module import name 的区别?如何避免命名冲突?为什么需要 if __name__ == '__main__'?今天一次性搞清楚!

一、为什么需要导入模块?

模块是包含Python代码的文件(.py文件),可以定义函数、类和变量,也可以包含可执行代码。模块让代码可以被组织和复用。

# 文件 math_utils.pydef add(a, b):    return a + bdef multiply(a, b):    return a * bPI = 3.14159

Python 的强大之处在于其丰富的生态系统。导入模块让我们能够:

  1. 复用代码:使用标准库或第三方库,避免重复造轮子。
  2. 组织代码:将大型项目拆分为多个文件,便于维护。
  3. 命名空间隔离:避免不同模块间的变量名冲突。

二、两种主要导入方式

1. import 模块名

导入整个模块,使用时需要加上模块名作为前缀。

import mathprint(math.sqrt(16))  # 4.0print(math.pi)        # 3.141592653589793
  • ✅ 优点:命名空间清晰,知道函数来自哪个模块,避免冲突。
  • ❌ 缺点:代码稍长,每次调用都要写前缀。

2. from 模块名 import 成员名

直接从模块中导入特定的函数、类或变量,使用时无需前缀。

from math import pi, sqrtprint(pi)            # 3.14159...print(sqrt(16))      # 4.0
  • ✅ 优点:代码简洁,调用方便。
  • ❌ 缺点:如果导入过多,可能不清楚函数来源;容易与本地变量名冲突。

三、导入方式的对比与选择

特性

import module

from module import name

调用方式

module.name()

name()

命名空间

独立,不易冲突

导入到当前 namespace,可能冲突

可读性

清楚来源

简洁,但来源不明显

性能

略优(只加载一次引用)

略低(复制引用到当前域)

推荐场景

使用模块中多个功能

只使用模块中个别功能

示例:命名冲突

# 假设我们有一个自定义函数叫 maxdef max(a, b):    return a if a > b else b# ❌ 冲突:内置的 max 被覆盖了from builtins import max  # 这行实际上不会生效,因为本地 def 优先# ✅ 安全:使用 import 保留前缀import builtinsresult = builtins.max(1, 2) # 明确使用内置的 max

四、特殊导入用法

1. 使用别名 (as)

当模块名太长,或需要避免冲突时,可以使用别名。

# 模块别名import matplotlib.pyplot as pltimport numpy as np# 成员别名from math import sqrt as square_rootprint(square_root(9))  # 3.0

2. 导入所有成员 (*) ⚠️

from math import *print(pi)  # 可以使用,但不推荐
  • ❌ 严重不推荐:
    1. 污染命名空间:你不知道导入了什么名字。
    2. 可读性差:看到 sqrt 不知道来自哪里。
    3. 隐藏冲突:可能覆盖现有变量。
  • ✅ 例外:仅在交互式命令行测试或特定框架(如 from tkinter import *)中偶尔使用。

3. 相对导入 (Relative Import)

在包内部,可以使用 . 表示当前包,.. 表示上一级包。

# 当前包内的 sibling.pyfrom . import sibling# 上一级包内的 module.pyfrom .. import module

⚠️ 注意:相对导入只能在包内部使用,主程序入口通常使用绝对导入。

五、核心机制:if __name__ == '__main__':

这是理解模块导入最关键的概念。

1. __name__ 变量

每个 Python 文件都有一个内置变量 __name__。

  • 直接运行文件:__name__ 的值为 '__main__'。
  • 被导入文件:__name__ 的值为 '模块名'。

2. 作用

确保代码块只在直接运行时执行,而在被导入时不执行。

示例:

# my_module.pydef func():    print("函数被调用")print("模块被加载了")if __name__ == '__main__':    print("主程序运行")    func()

运行 python my_module.py:

模块被加载了主程序运行函数被调用

在其他文件 import my_module:

模块被加载了# (不会打印"主程序运行")

💡 最佳实践:所有可执行脚本都应包含此 guard,以便代码既能作为脚本运行,又能作为模块被导入。

六、导入搜索路径 (sys.path)

当你在代码中 import xxx 时,Python 去哪里找这个模块?

import sysprint(sys.path)

搜索顺序:

  1. 当前脚本所在目录。
  2. PYTHONPATH 环境变量中的目录。
  3. 标准库目录。
  4. 第三方库目录 (site-packages)。

⚠️ 常见错误:导入失败 ModuleNotFoundError 通常是因为模块不在上述路径中。

七、最佳实践 (PEP 8)

1. 导入顺序

通常分为三组,每组之间空一行:

  1. 标准库 (如 os, sys)
  2. 第三方库 (如 numpy, requests)
  3. 本地应用/自定义模块 (如 my_module)
import osimport sysimport numpy as npimport requestsfrom my_project import utils

2. 避免循环导入

  • 现象:A 导入 B,B 又导入 A。
  • 后果:报错 ImportError 或部分内容为空。
  • 解决:重构代码,将公共部分提取到第三个模块 C,让 A 和 B 都导入 C。

3. 不要在导入行执行逻辑

# ❌ 不推荐import os; os.mkdir('test')# ✅ 推荐import osos.mkdir('test')

4.使用模块中的内容

导入模块后,使用模块名.成员的方式访问:

import osprint(os.getcwd())  # 获取当前工作目录print(os.name)      # 操作系统名称

5.导入多个模块

# 分开导入(推荐)import osimport sysimport json# 一行导入(不推荐,可读性差)import os, sys, json

6.使用别名(as)

import numpy as npimport pandas as pdimport matplotlib.pyplot as plt# 使用别名访问arr = np.array([1, 2, 3])

7. from...import导入特定成员

from math import sqrt, pi# 直接使用,不需要模块名前缀print(sqrt(16))  # 4.0print(pi)        # 3.141592653589793

8. from...import导入多个成员

from os.path import join, exists, dirnamepath = join("folder", "file.txt")print(exists(path))

9. 使用别名

from datetime import datetime as dtnow = dt.now()print(now)

10.导入所有成员(不推荐)

from math import *# 可以直接使用所有math模块的成员print(sqrt(16))print(sin(0))print(cos(0))

11.导入包中的模块

# 导入包中的模块import mypackage.module1mypackage.module1.some_function()# 使用from...importfrom mypackage import module1module1.some_function()# 直接导入函数from mypackage.module1 import some_functionsome_function()# 导入子包中的模块from mypackage.subpackage import module3

12.绝对导入

从项目根目录开始的完整路径:

from mypackage.subpackage import module3from mypackage.module1 import func1

13.相对导入

使用点号表示相对位置(只能在包内使用):

# 在mypackage/module2.py中# 导入同级模块from . import module1# 导入同级模块的成员from .module1 import func1# 导入上级包from .. import other_package# 导入上级包的模块from ..other_package import module

八、import 与 from...import 对比

特性import modulefrom module import name
访问方式module.namename
命名空间保持独立直接引入当前空间
代码长度较长较短
可读性来源清晰需要记忆来源
名称冲突不易冲突可能冲突
# import方式import mathprint(math.sqrt(16))  # 来源清晰# from...import方式from math import sqrtprint(sqrt(16))  # 更简洁

九、总结

概念

说明

import module

导入整个模块,需加前缀,安全

from import

导入特定成员,无前缀,简洁

**import * **

导入所有,污染命名空间,避免使用

as 别名

简化名称或避免冲突

name

'__main__' 表示直接运行,否则为模块名

搜索路径

sys.path 决定导入查找顺序


📌 明日预告:

明天我们将专门深入探讨 __name__ == "__main__" 的核心作用!

虽然我们在今天简要提到了它,但这个机制是 Python 脚本与模块区别的基石,值得单独一天来彻底掌握。

  • 为什么需要区分“直接运行”和“被导入”?
  • 它在大型项目架构中如何防止代码意外执行?
  • 如何利用它编写可测试、可复用的代码?
  • 常见的误区与最佳实践有哪些?

掌握这一机制,你将真正理解 Python 程序的执行入口,为后续学习面向对象编程打下坚实基础!

准备好深入理解 Python 的入口逻辑了吗?继续加油!🚀

最新文章

随机文章