当前位置:首页>python>Python零基础入门(四):模块与包导入

Python零基础入门(四):模块与包导入

  • 2026-10-10 12:05:09
Python零基础入门(四):模块与包导入

前言

前三篇我们一路从环境搭建与数据类型、运算符与条件判断学到了面向对象编程基础。你写的代码越来越长、功能越来越多——于是问题来了:所有代码都塞在一个文件里,动辄上千行,该怎么管?

答案就是模块(Module) 。模块让你把代码拆分到多个文件中,各自独立、按需复用。Python 标准库就是由数百个模块组成的,学会模块机制,你才算真正掌握了 Python 的"拼图"方式。


一、模块是什么?

一个.py文件就是一个模块。文件名去掉 .py 后缀就是模块名。

my_project/├── main.py          # 入口文件├── calculator.py    # 模块:计算器└── utils.py         # 模块:工具函数

在 calculator.py 中写一些函数:

# calculator.py"""计算器模块 —— 提供基本的数学运算"""def add(a, b):    return a + bdef subtract(a, b):    return a - bdef multiply(a, b):    return a * bdef divide(a, b):    if b == 0:        raise ValueError("除数不能为零")    return a / b# 模块级常量PI = 3.14159

在 main.py 中使用它:

# main.pyimport calculatorprint(calculator.add(10, 5))      # 15print(calculator.PI)              # 3.14159

就是这么简单——import 模块名,然后用 模块名.函数名() 调用。模块让代码组织变得自然:一个文件负责一类功能。


二、import 的四种写法

Python 的导入语法非常灵活,四种写法应付不同场景:

2.1 最基础:import 模块名

import mathprint(math.sqrt(16))   # 4.0print(math.pi)         # 3.141592653589793

每次使用都要带 模块名. 前缀,清晰明了,不会污染当前命名空间。

2.2 起别名:import 模块名 as 别名

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltarr = np.array([1, 2, 3])data = pd.DataFrame({"a": [1, 2, 3]})plt.plot([1, 2, 3], [4, 5, 6])

社区有约定俗成的别名:numpy → np,pandas → pd,matplotlib.pyplot → plt。跟着约定走,别人一看就懂。

2.3 按需导入:from 模块 import 名字

from math import sqrt, pi, cosprint(sqrt(25))   # 5.0 —— 直接写函数名,不用加 math.print(pi)         # 3.141592653589793print(cos(0))     # 1.0

好处是代码更简洁,坏处是可能和当前文件里的函数重名。使用时注意避让。

2.4 全量导入(谨慎使用):from 模块 import *

from math import *print(sin(0))     # 0.0print(e)          # 2.718281828459045

不推荐!  它会把这个模块里所有公开的名字全部塞进当前命名空间,你根本不知道导入了什么,极易造成命名冲突。只在极少数场景(如 tkinter 的常量定义)用到。


三、if __name__ == "__main__" 到底什么意思?

这是 Python 面试必考题,也是每个 Python 文件都该有的"入口守门员"。

3.1 先看现象

创建 greet.py:

# greet.pydef hello(name):    return f"你好,{name}!"print(f"greet.py 的 __name__ 是:{__name__}")if __name__ == "__main__":    print("我作为主程序运行")    print(hello("世界"))

直接运行它:

$ python greet.pygreet.py 的 __name__ 是:__main__我作为主程序运行你好,世界!

再创建 app.py 导入它:

# app.pyimport greetprint("app.py 结束")
$ python app.pygreet.py 的 __name__ 是:greetapp.py 结束

3.2 规则很简单

运行方式
__name__
 的值
直接执行 (python xxx.py)
"__main__"
被导入 (import xxx)
模块名 "xxx"

所以 if __name__ == "__main__": 的意思是:这个文件只有当被直接运行时才执行这段代码,被导入时跳过。

3.3 为什么需要它?

# 不好 —— 每次导入都会执行print("模块加载中...")run_tests()          # 别人 import 时也会跑测试!# 好 —— 只在直接运行时执行if __name__ == "__main__":    print("模块加载中...")    run_tests()      # 只有 python xxx.py 时才跑

建议:每个 .py 文件都加上 if __name__ == "__main__":,哪怕里面暂时只有一行 pass。这是一个好习惯,日后扩展时才不会踩坑。


四、模块搜索路径:Python 怎么找到你的模块?

当你写 import something,Python 会按顺序在以下路径中搜索:

import sysfor p in sys.path:    print(p)

典型输出:

(当前脚本所在目录)/usr/lib/python3.10/usr/lib/python3.10/lib-dynload/home/user/miniconda3/envs/myproject/lib/python3.10/site-packages

搜索顺序:

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

如果模块找不到,先检查这几处。常见解决方案:

# 临时添加搜索路径(不推荐,但应急可用)import syssys.path.append("/path/to/your/module")

更好的做法是正确组织项目结构,用包来管理。


五、包(Package):组织模块的文件夹

模块多了怎么办?用包——包含 __init__.py 的文件夹就是包。

5.1 包的基本结构

my_project/├── main.py├── mathlib/                # 这是一个包│   ├── __init__.py          # 标识此文件夹为包(可为空)│   ├── arithmetic.py        # 子模块:四则运算│   └── advanced.py          # 子模块:高级运算└── utils/                   # 另一个包    ├── __init__.py    ├── fileio.py    └── logger.py

__init__.py 是包的身份证。Python 3.3 起虽然没有 __init__.py 也不报错(称为"命名空间包"),但建议始终放一个,即使是空文件,明确表示"这是一个包"。

5.2 导入包中的模块

# 方式一:导入完整路径import mathlib.arithmeticprint(mathlib.arithmetic.add(3, 4))# 方式二:from 导入from mathlib.arithmetic import add, subtractprint(add(3, 4))# 方式三:from 包导入模块from mathlib import advancedprint(advanced.power(2, 10))# 方式四:别名import mathlib.advanced as advprint(adv.sqrt(16))

5.3 用 init.py 统一出口

__init__.py 不只是标识,还能控制 from 包 import * 的行为和简化接口:

# mathlib/__init__.pyfrom .arithmetic import add, subtract, multiply, dividefrom .advanced import power, sqrt, factorial__all__ = ["add", "subtract", "multiply", "divide", "power", "sqrt", "factorial"]

这样外部使用变得非常简洁:

from mathlib import add, powerprint(add(1, 2))     # 3print(power(2, 8))   # 256

5.4 相对导入:包内部互相引用

在包内部,子模块之间引用用相对导入:

# mathlib/advanced.pyfrom .arithmetic import multiply    # . 表示"当前包"def power(base, exp):    """用 multiply 实现乘方"""    result = 1    for _ in range(exp):        result = multiply(result, base)    return result# mathlib/arithmetic.py 中引用上级同级from . import advanced              # 导入同一个包下的 advancedfrom ..utils import logger          # .. 表示上级包

相对导入规则速查:

符号
含义
.
当前包(本文件所在目录)
..
上级包
...
上上级包
.module
当前包下的 module 模块
..package.module
上级包下的 package 的子模块

注意:相对导入只能在包内部使用。如果直接运行一个使用了相对导入的 .py 文件(如 python arithmetic.py),会报错 ImportError: attempted relative import with no known parent package。此时需要从包外部以模块方式运行(python -m mathlib.arithmetic)。


六、常用标准库速览

Python 自带了大量实用模块,下面是最常用的一批:

模块
用途
一行示例
os
操作系统接口(路径、环境变量)
os.path.join("a", "b")
sys
系统参数与运行时信息
sys.argv[1]
 → 获取命令行参数
math
数学函数
math.sqrt(16)
 → 4.0
random
随机数
random.randint(1, 10)
datetime
日期时间处理
datetime.datetime.now()
json
JSON 编解码
json.loads('{"a": 1}')
re
正则表达式
re.search(r"\d+", "abc123")
os.path
路径操作
os.path.exists("/tmp/test.txt")
shutil
高级文件操作
shutil.copy("a.txt", "b.txt")
argparse
命令行参数解析
构建专业的命令行工具
typing
类型提示
def f(x: int) -> str:
# 综合示例:5 行代码创建一个带时间戳的文件import jsonfrom datetime import datetimedata = {"name": "测试", "timestamp": datetime.now().isoformat(), "value": 42}with open("output.json", "w", encoding="utf-8") as f:    json.dump(data, f, ensure_ascii=False, indent=2)print("文件已生成:output.json")

七、第三方包与 pip

Python 的"标准库"只是开胃菜,真正的盛宴在 PyPI(Python Package Index),上面的第三方包数量超过 40 万。

7.1 基础操作

# 安装pip install requests# 安装指定版本pip install numpy==1.24.0# 卸载pip uninstall requests# 查看已安装的包pip list# 导出依赖列表pip freeze > requirements.txt# 根据依赖列表批量安装pip install -r requirements.txt

国内用户建议使用清华镜像加速,详见本系列第一篇的 1.4 节。

7.2 新手必知的几个第三方包

包名
一句话介绍
requests
HTTP 请求,比标准库的 urllib 好用百倍
numpy
科学计算的基础——高性能多维数组
pandas
数据分析利器——DataFrame 表格处理
matplotlib
数据可视化——画图、图表
pillow
图像处理——打开、编辑、保存图片
flask
轻量级 Web 框架——几行代码搭网站

7.3 靠谱的项目依赖方案

# 用虚拟环境隔离依赖(第一篇讲过)conda create -n myproject python=3.10 -yconda activate myproject# 安装依赖pip install requests pandas matplotlib# 锁定版本pip freeze > requirements.txt

requirements.txt 示例:

numpy==1.24.0pandas==2.1.0matplotlib==3.7.1requests==2.31.0

把 requirements.txt 放在项目根目录,其他人 pip install -r requirements.txt 就能复现你的环境。


八、动手练习

  1. 1. 创建一个 string_utils.py 模块,包含 reverse_str(text)(反转字符串)和 count_words(text)(统计单词数)两个函数。在 main.py 中导入并使用。
  2. 2. 建一个包 shapes,包含 circle.py(面积、周长)和 rectangle.py(面积、周长)。在 __init__.py 中统一导出接口,然后在 main.py 中用 from shapes import circle_area, rect_area 的方式调用。
  3. 3. 在练习 2 的包中,让 circle.py 和 rectangle.py 使用 if __name__ == "__main__": 各自包含一段测试代码。
  4. 4. 安装 requests 包,写一个脚本请求 https://api.github.com,打印返回的 JSON 中 current_user_url 字段的值。

九、小结

本篇我们从"一个文件就是一个模块"出发,系统掌握了 Python 的模块与包体系:

  • • import 的四种写法:import、import...as、from...import、from...import *,各有适用场景。
  • •  __name__魔法:区分"直接运行"与"被导入",每个文件都该加上 if __name__ == "__main__":。
  • • 模块搜索路径:sys.path 决定 Python 在哪找模块,理解它就不会再困惑"为什么找不到模块"。
  • • 包:用文件夹 + __init__.py 组织模块,相对导入让包内部互相引用,__init__.py 统一对外接口。
  • • 标准库与第三方包:os、sys、json、datetime 等开箱即用,pip install 打开更广阔的世界。

模块是 Python 代码复用的基础单元。掌握了模块,你就能写出"分而治之"的干净代码,而不是一个几千行的巨型文件。


本文首发于微信公众号「羽您码上聊」,欢迎关注获取更多技术内容。

最新文章

随机文章