Python模块与包:import一行引入万千功能,代码组织的正确姿势
模块和包是Python代码组织的核心机制,使代码可以被复用和共享。理解import机制、标准库的使用以及第三方库的安装,是Python开发的必备技能。
1. 什么是模块
模块(Module)是一个包含Python代码的.py文件,可以定义函数、类和变量。
# mymodule.py - 这就是一个模块
"""这是模块的文档字符串"""
# 模块级变量
VERSION = "1.0.0"
# 函数
def greet(name):
return f"Hello, {name}!"
# 类
class Calculator:
def add(self, a, b):
return a + b
模块的好处:
- 代码复用:写一次,到处使用
- 命名空间:避免名称冲突
- 代码组织:将相关功能放在一起
2. 导入模块
2.1 import语句
# 导入整个模块
import math
print(math.pi) # 3.141592653589793
print(math.sqrt(16)) # 4.0
# 导入多个模块
import os
import sys
import json
# 或一行导入多个(不推荐)
import os, sys, json
2.2 from…import语句
# 从模块导入特定内容
from math import pi, sqrt
print(pi) # 3.141592653589793
print(sqrt(16)) # 4.0(不需要math.前缀)
# 导入所有内容(不推荐)
from math import *
print(sin(0)) # 0.0
# 为什么不推荐 import *?
# 1. 不清楚导入了什么
# 2. 可能覆盖已有名称
# 3. 代码可读性差
2.3 导入别名
# 模块别名
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 函数/类别名
from datetime import datetime as dt
now = dt.now()
# 常见的别名约定
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
import seaborn as sns
3. 创建自己的模块
# utils.py - 自定义工具模块
"""
工具函数模块
提供常用的辅助函数
"""
__version__ = "1.0.0"
__author__ = "Your Name"
def add(a, b):
"""两数相加"""
return a + b
def multiply(a, b):
"""两数相乘"""
return a * b
def is_even(n):
"""判断是否为偶数"""
return n % 2 == 0
class MathHelper:
"""数学辅助类"""
@staticmethod
def factorial(n):
"""计算阶乘"""
if n <= 1:
return 1
return n * MathHelper.factorial(n - 1)
# 模块级别的初始化代码
print("utils模块已加载")
# main.py - 使用自定义模块
import utils
print(utils.add(1, 2)) # 3
print(utils.is_even(4)) # True
print(utils.MathHelper.factorial(5)) # 120
from utils import add, multiply
print(add(3, 4)) # 7
4. 包(Package)
包是包含多个模块的目录,必须包含__init__.py文件。
mypackage/
├── __init__.py # 包的初始化文件
├── module1.py
├── module2.py
└── subpackage/ # 子包
├── __init__.py
└── module3.py
# mypackage/__init__.py
"""mypackage包"""
from .module1 import func1
from .module2 import func2
__all__ = ['func1', 'func2'] # 定义 from package import * 导入的内容
# mypackage/module1.py
def func1():
return "func1 from module1"
# mypackage/module2.py
def func2():
return "func2 from module2"
# mypackage/subpackage/__init__.py
from .module3 import func3
# mypackage/subpackage/module3.py
def func3():
return "func3 from subpackage"
# 使用包
import mypackage
print(mypackage.func1())
from mypackage import func1, func2
print(func1())
from mypackage.subpackage import func3
print(func3())
from mypackage.module1 import func1
print(func1())
5. __name__变量
__name__是一个特殊变量,用于判断模块是被导入还是直接运行。
# mymodule.py
def main():
print("主程序执行")
def helper():
print("辅助函数")
# 当模块被直接运行时,__name__ == "__main__"
# 当模块被导入时,__name__ == "mymodule"
if __name__ == "__main__":
# 只有直接运行此文件时才执行
print("直接运行模块")
main()
else:
print(f"模块被导入,__name__ = {__name__}")
# 运行 python mymodule.py
# 输出:直接运行模块
# 主程序执行
# 在其他文件中 import mymodule
# 输出:模块被导入,__name__ = mymodule
典型用法:
# calculator.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def main():
"""测试代码"""
print(f"1 + 2 = {add(1, 2)}")
print(f"5 - 3 = {subtract(5, 3)}")
if __name__ == "__main__":
main()
6. 模块搜索路径
Python按以下顺序搜索模块:
- 当前目录
- 环境变量PYTHONPATH中的目录
- 标准库目录
- site-packages目录(第三方库)
import sys
# 查看模块搜索路径
for path in sys.path:
print(path)
# 添加自定义搜索路径
sys.path.append('/path/to/my/modules')
# 查看模块位置
import os
print(os.__file__) # 显示os模块的文件路径
# 查看已导入的模块
print(sys.modules.keys())
7. 标准库概览
Python标准库提供了丰富的功能模块:
| 类别 | 模块 | 功能 |
|---|---|---|
| 文件/目录 | os, pathlib, shutil | 文件系统操作 |
| 数据格式 | json, csv, xml | 数据序列化 |
| 日期时间 | datetime, time, calendar | 时间处理 |
| 数学 | math, random, statistics | 数学计算 |
| 字符串 | re, string, textwrap | 字符串处理 |
| 网络 | urllib, http, socket | 网络通信 |
| 并发 | threading, multiprocessing, asyncio | 并发编程 |
| 数据结构 | collections, itertools, functools | 高级数据结构 |
| 调试 | logging, pdb, traceback | 调试和日志 |
| 系统 | sys, os, platform | 系统交互 |
# 常用标准库示例
# os - 操作系统接口
import os
print(os.getcwd()) # 当前目录
print(os.listdir('.')) # 列出目录内容
os.makedirs('new/dir', exist_ok=True) # 创建目录
# datetime - 日期时间
from datetime import datetime, timedelta
now = datetime.now()
print(now.strftime('%Y-%m-%d %H:%M:%S'))
tomorrow = now + timedelta(days=1)
# json - JSON处理
import json
data = {'name': '张三', 'age': 25}
json_str = json.dumps(data, ensure_ascii=False)
data = json.loads(json_str)
# re - 正则表达式
import re
pattern = r'\d+'
matches = re.findall(pattern, 'abc123def456')
# collections - 高级数据结构
from collections import Counter, defaultdict, namedtuple
counter = Counter(['a', 'b', 'a', 'c', 'a'])
print(counter.most_common(2)) # [('a', 3), ('b', 1)]
# random - 随机数
import random
print(random.randint(1, 100))
print(random.choice(['a', 'b', 'c']))
random.shuffle([1, 2, 3, 4, 5])
# logging - 日志
import logging
logging.basicConfig(level=logging.INFO)
logging.info('这是一条日志')
8. 第三方库安装
使用pip安装第三方库:
# 安装包
pip install package_name
pip install pandas
pip install numpy==1.24.0 # 指定版本
pip install "numpy>=1.20,<2.0" # 版本范围
# 升级包
pip install --upgrade package_name
pip install -U pandas
# 卸载包
pip uninstall package_name
# 查看已安装的包
pip list
pip show pandas # 查看包详情
# 导出依赖
pip freeze > requirements.txt
# 从文件安装
pip install -r requirements.txt
# 使用国内镜像
pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple
常用第三方库:
| 领域 | 库 | 用途 |
|---|---|---|
| 数据处理 | pandas, numpy | 数据分析 |
| 可视化 | matplotlib, seaborn | 图表绑制 |
| Web开发 | Flask, Django, FastAPI | Web框架 |
| 网络请求 | requests | HTTP客户端 |
| 办公自动化 | openpyxl, python-docx, python-pptx | Office文件 |
| 串口通信 | pyserial | 串口操作 |
| GUI | PyQt5, tkinter | 图形界面 |
9. 虚拟环境
虚拟环境为每个项目创建独立的Python环境。
# 创建虚拟环境
python -m venv .venv
# 激活虚拟环境
# Windows CMD
.venv\Scripts\activate
# Windows PowerShell
.venv\Scripts\Activate.ps1
# Linux/Mac
source .venv/bin/activate
# 退出虚拟环境
deactivate
# 在虚拟环境中安装包
pip install pandas
# 导出依赖
pip freeze > requirements.txt
# 在新环境中安装依赖
pip install -r requirements.txt
项目结构示例:
my_project/
├── .venv/ # 虚拟环境(不提交到Git)
├── src/
│ ├── __init__.py
│ └── main.py
├── tests/
├── requirements.txt # 依赖列表
├── README.md
└── .gitignore # 包含.venv/
10. 常见错误与避坑
❌ 错误1:循环导入
# a.py
from b import func_b
def func_a():
return "a"
# b.py
from a import func_a # 循环导入!
def func_b():
return "b"
# 解决方案:
# 1. 重构代码,消除循环依赖
# 2. 将导入放在函数内部
# 3. 使用延迟导入
❌ 错误2:模块名与标准库冲突
# 错误:创建了名为 random.py 的文件
# 会覆盖标准库的random模块
# 正确:使用不同的名称
# my_random.py 或 random_utils.py
❌ 错误3:相对导入错误
# 在包内使用相对导入
# mypackage/module1.py
from .module2 import func # 正确
from module2 import func # 可能出错
# 相对导入只能在包内使用
# 直接运行模块时会报错
❌ 错误4:修改模块后不生效
# 模块只会被导入一次
# 修改后需要重新加载
import importlib
import mymodule
# 重新加载模块
importlib.reload(mymodule)
11. 实战练习
练习1:创建工具包
"""
练习:创建一个工具包,包含文件操作和字符串处理功能
目录结构:
mytools/
├── __init__.py
├── fileutils.py
└── strutils.py
"""
# mytools/__init__.py
from .fileutils import read_file, write_file
from .strutils import clean_text, extract_numbers
__version__ = "1.0.0"
__all__ = ['read_file', 'write_file', 'clean_text', 'extract_numbers']
# mytools/fileutils.py
from pathlib import Path
def read_file(filepath, encoding='utf-8'):
"""读取文件内容"""
return Path(filepath).read_text(encoding=encoding)
def write_file(filepath, content, encoding='utf-8'):
"""写入文件内容"""
Path(filepath).write_text(content, encoding=encoding)
# mytools/strutils.py
import re
def clean_text(text):
"""清理文本"""
return ' '.join(text.split())
def extract_numbers(text):
"""提取文本中的数字"""
return [int(n) for n in re.findall(r'\d+', text)]
练习2:配置管理模块
"""
练习:创建配置管理模块
"""
# config.py
import json
from pathlib import Path
class Config:
"""配置管理类"""
def __init__(self, config_file='config.json'):
self.config_file = Path(config_file)
self._config = {}
self.load()
def load(self):
"""加载配置"""
if self.config_file.exists():
self._config = json.loads(
self.config_file.read_text(encoding='utf-8')
)
def save(self):
"""保存配置"""
self.config_file.write_text(
json.dumps(self._config, ensure_ascii=False, indent=2),
encoding='utf-8'
)
def get(self, key, default=None):
"""获取配置项"""
return self._config.get(key, default)
def set(self, key, value):
"""设置配置项"""
self._config[key] = value
self.save()
# 使用
if __name__ == "__main__":
config = Config()
config.set('debug', True)
config.set('database', {'host': 'localhost', 'port': 3306})
print(config.get('debug'))
12. 总结
🔑 核心要点
| 知识点 | 要点 |
|---|---|
| 模块 | 一个.py文件就是一个模块 |
| 包 | 包含__init__.py的目录 |
| import | 导入整个模块 |
| from…import | 导入特定内容 |
| __name__ | 判断模块是被导入还是直接运行 |
| pip | 安装第三方库 |
| 虚拟环境 | 项目隔离的Python环境 |
✅ 学习检查清单
- 理解模块和包的概念
- 掌握各种import方式
- 能创建自己的模块和包
- 理解__name__的作用
- 能使用pip安装第三方库
- 能创建和使用虚拟环境
📖 下一步学习
掌握了模块与包后,让我们学习Python的面向对象编程:
常见问题 FAQ
💬 import和from...import哪个好?
import module更安全,避免命名冲突。from module import func更方便但要注意重名。大型项目建议用import module然后module.func()调用。
💬 if __name__ == "__main__":有什么用?
这行让文件既可以作为模块被import,也可以直接运行。import时__name__是模块名,直接运行时是"__main__"。几乎每个Python脚本都应该加这行。
� 系列导航
- 上一篇:11 - Python异常处理
- 当前:12 - Python模块与包
- 下一篇:13 - Python面向对象编程