# 概述 # 模块和包是 Python 中组织代码的重要方式,它们让代码更加结构化、可维护和可重用。掌握模块和包的使用是 Python 编程的基础技能。 # 2.核心概念 # 模块:包含 Python 定义和语句的 .py 文件 # 包:包含多个模块的目录,必须有 __init__.py 文件 # 命名空间:每个模块和包都有独立的命名空间 # 导入:将模块或包引入当前程序的过程 # 模块(Module) # 3.1.什么是模块? # 模块是一个包含 Python 定义和语句的 .py 文件,可以包含: # 函数定义 # 类定义 # 变量 # 可执行代码 # 3.2.模块的优势 # 代码复用:公共函数/类可以集中管理 # 命名空间隔离:避免命名冲突 # 可维护性:分文件组织更易管理大型项目 # 模块化设计:提高代码的模块化程度 # 创建和使用模块 # 创建模块 # mymodule.py def hello(): print("Hello from mymodule!") def add(a, b): return a + b class Calculator: def multiply(self, a, b): return a * b # 导入模块 # main.py import mymodule # 使用模块中的函数和类 mymodule.hello() result = mymodule.add(3, 4) calc = mymodule.Calculator() print(calc.multiply(2, 3)) # 导入特定成员 # 导入特定函数和类 from mymodule import hello, add, Calculator # 直接使用,无需模块名前缀 hello() result = add(3, 4) calc = Calculator() # 模块查找路径 # Python 按照以下顺序查找模块: # 当前程序所在目录 # PYTHONPATH 环境变量指定的目录 # Python 安装时的标准库目录 import sys # 查看模块搜索路径 print(sys.path) # 模块命名规范 # 使用小写字母和下划线 # 避免与标准库同名 # 导入时无需写 .py 后缀 # 导入方式详解 # 导入整个模块 # import math # # 通过模块名访问成员 # print(math.sqrt(16)) # 输出 4.0 # print(math.pi) # 输出 3.141592653589793 # 1.优点 # 命名空间清晰:明确成员来自哪个模块 # 避免命名冲突:同名函数不会冲突 # 代码可读性:容易理解函数来源 # 2.适用场景 # 使用模块中多个成员时 # 需要明确函数来源时 # 避免命名冲突时 # 导入所有成员(import *) # from 模块名 import * # mymodule.py def foo(): print("foo") def bar(): print("bar") from mymodule import * foo() # 输出 foo bar() # 输出 bar # 控制导入内容 # mymodule.py __all__ = ["foo"] # 只允许导入 foo def foo(): print("foo") def bar(): print("bar") # 注意事项 # 不推荐使用:容易造成命名冲突 # 仅限模块:不适用于包 # 命名空间污染:直接暴露在当前命名空间 # 可读性差:难以确定函数来源 # 推荐做法 # 推荐:明确导入 from mymodule import foo, bar # 推荐:导入整个模块 import mymodule # 使用别名 # import 模块名 as 新名字 # from 模块名 import 成员 as 新名字 # 示例 import numpy as np import matplotlib.pyplot as plt from math import factorial as fact # 使用别名 arr = np.array([1, 2, 3]) plt.plot([1, 2, 3]) result = fact(5) # 别名优势 # 代码简洁:缩短长模块名 # 避免冲突:解决命名冲突 # 社区约定:遵循常用别名习惯 # 常用别名 # numpy → np # pandas → pd # matplotlib.pyplot → plt # tensorflow → tf # 模块的 __name__ 属性 # __name__ 属性用于判断模块是被直接运行还是被导入: # 直接运行时:__name__ 为 "__main__" # 被导入时:__name__ 为模块名称 # mymodule.py def func(): print("hello") if __name__ == "__main__": # 只在直接运行时执行 func() # 使用场景 # 运行方式 __name__ 值 作用 # 直接运行 "__main__" 执行主流程 # 被导入 模块名 提供接口 # 最佳实践 # 所有模块入口脚本都使用 if __name__ == "__main__": # 既可作为工具库导入,也可作为脚本运行 # 提高代码的灵活性和可测试性 # 包(Package) # 5.1.什么是包? # 包是组织多个模块的目录,包含: # 多个模块(.py 文件) # 子包(嵌套目录) # __init__.py 文件(必需) # 5.2.包的优势 # 项目结构清晰:分层组织代码 # 避免命名冲突:独立的命名空间 # 便于团队开发:模块化协作 # 组件重用:可复用的代码单元 # 包的结构 # mypackage/ # ├── __init__.py # 包初始化文件(必需) # ├── module1.py # 模块1 # ├── module2.py # 模块2 # └── subpackage/ # 子包 # ├── __init__.py # 子包初始化文件 # └── module3.py # 子包模块 # 创建包结构 # 目录结构 # myproject/ # ├── main.py # └── mypackage/ # ├── __init__.py # ├── module1.py # ├── module2.py # └── subpackage/ # ├── __init__.py # └── module3.py # 初始化文件 __init__.py # mypackage/__init__.py """mypackage 包的初始化文件""" __version__ = "1.0.0" __author__ = "Your Name" # 导入包中的模块,方便用户使用 from .module1 import function1 from .module2 import Class2 # 定义包级别的变量 package_variable = "这是包变量" print("mypackage 包被导入") # 包中的模块 # mypackage/module1.py def function1(): return "这是 module1 的 function1" def helper_function(): return "辅助函数" # mypackage/module2.py class Class2: def __init__(self, value): self.value = value def display(self): return f"Class2 的值: {self.value}" # mypackage/subpackage/module3.py def function3(): return "这是子包中的 function3" # 导入包和模块语法 # 导入整个包 # 导入整个包(执行 __init__.py) import mypackage # 导入包内模块 # 导入包内指定模块 from mypackage import module1 # 导入包中模块的成员 from mypackage.module1 import function1 # 导入子包 # 导入子包中的模块 from mypackage.subpackage import module3 # 导入子包模块的成员 from mypackage.subpackage.module3 import function3 # 相对导入与绝对导入 # 绝对导入 # 从项目根包开始写完整路径: # 从 mypackage 包中的 module1 模块导入 function1 函数 from mypackage.module1 import function1 # 从子包中导入 from mypackage.subpackage.module3 import function3 # 相对导入 # 在包内部使用点号语法: # 同级目录 from . import module1 # 上一级包 from .. import module2 # 同级模块 from .module1 import func # 上级包的子包 from ..subpackage import module3 # 注意事项 # 相对导入只能用于包内部模块 # 不能在最顶层脚本(main.py)中使用 # 包内各文件的相对路径以包目录为基准 # __init__.py 的作用 # 声明包:标识目录为 Python 包 # 初始化操作:包级变量、配置、统一导入 # 控制导入:通过 __all__ 列表控制可见成员 # 导入包和模块示例 # main.py # 导入包中的特定模块 from mypackage import module1 print(module1.function1()) # 导入包中的特定函数/类 from mypackage.module2 import Class2 obj = Class2(42) print(obj.display()) # 导入子包中的模块 from mypackage.subpackage import module3 print(module3.function3()) # 使用 __init__.py 中导入的内容 from mypackage import function1 print(function1()) # 导入包变量 import mypackage print(mypackage.package_variable) # 高级导入技巧 # 相对导入 # 相对导入在包内部使用点号语法引用同包或父包内容: # 基本语法 # from . import xxx:从当前包导入 # from .. import xxx:从父包导入 # from .subpackage import yyy:从子包导入 # mypackage/ # ├── __init__.py # ├── module1.py # ├── module2.py # └── subpackage/ # ├── __init__.py # └── module3.py # module1.py # from . import module2 # 导入同级模块 # from .subpackage import module3 # 导入子包模块 # def function1(): # return "这是 module1 的 function1" # 注意事项 # 只能在包内部使用 # 不能在主程序(main.py)中使用 # 有助于包的重命名与迁移 # 点数与目录层次相关 # 动态导入 # 动态导入在程序运行时根据需要导入模块,常用于插件系统和可扩展框架。 # .使用 __import__() module_name = "math" math_module = __import__(module_name) print(math_module.sqrt(9)) # 输出: 3.0 # 使用 importlib import importlib # 导入标准库模块 module = importlib.import_module("json") data = module.loads('{"a": 1}') print(data) # 输出: {'a': 1} # 导入包内模块 module_name = "mypackage.module1" mod = importlib.import_module(module_name) result = mod.function1() print(result) # 输出: 这是 module1 的 function1 # 动态导入优势 # 按需加载:减少资源占用 # 插件机制:支持动态扩展功能 # 配置驱动:根据配置加载不同组件 # 注意事项 # 确保模块名合法且可找到 # 过度使用影响代码可读性 # 仅在确有需要时使用 # 模块搜索路径 # 搜索路径顺序 # Python 按以下顺序查找模块: # 当前脚本所在目录 # 标准库路径(如 /usr/lib/python3.x) # 第三方库目录(如 site-packages) # PYTHONPATH 环境变量指定的路径 # 查看和修改搜索路径 import sys # 查看当前搜索路径 print(sys.path) # 临时添加自定义路径 sys.path.append("/path/to/your/modules") # 模块查找优先级 # 内存缓存:已加载的模块(防止重复导入) # 内建模块:如 sys、os # sys.path 目录:按顺序逐一查找 # 最佳实践 # 合理组织项目结构 # 使用 __init__.py 标识包 # 规范包和模块命名 # 避免随意修改 sys.path # 创建可安装的包 # 包目录结构 # mypackage/ # ├── mypackage/ # │ ├── __init__.py # │ ├── module1.py # │ └── module2.py # ├── tests/ # │ └── test_module1.py # ├── setup.py # ├── README.md # └── LICENSE # 创建步骤 # 组织包目录结构 # 外层目录:项目根目录 # 内层目录:实际包目录(包含 __init__.py) # tests/:测试代码目录 # 创建 __init__.py # 声明目录为 Python 包 # 可包含包级初始化逻辑 # 编辑 setup.py 配置 # 声明包名称、版本、依赖等元信息 # (可选)增加 MANIFEST.in # 包含非 Python 文件(数据文件、README 等) # 安装和发布 # 本地安装:pip install . 或 pip install -e . # 发布到 PyPI:python setup.py sdist bdist_wheel 和 twine upload dist/* # 设置文件 setup.py # setup.py from setuptools import setup, find_packages setup( name="mypackage", version="1.0.0", description="一个示例包", author="Your Name", packages=find_packages(), install_requires=[ "requests>=2.25.1", "numpy>=1.19.5", ], python_requires=">=3.6", ) # 安装和发布 # 开发模式安装(可编辑模式) pip install -e . # 构建分发包 python setup.py sdist bdist_wheel # 上传到PyPI twine upload dist/* # 最佳实践 # 1.命名规范 # 模块命名:使用小写字母和下划线 # 包命名:使用小写字母,避免使用下划线 # 避免冲突:不与标准库同名 # 2.导入规范 # 导入顺序:标准库 → 第三方库 → 本地模块 # 避免循环导入:模块间相互导入 # 使用 if __name__ == "__main__":区分直接运行和导入 # 导入顺序示例 # 标准库 import os import sys from datetime import datetime # 第三方库 import requests import numpy as np # 本地模块 from mypackage import module1 from mypackage.subpackage import module2 # 项目组织 # 合理使用包和模块 # 避免过深的嵌套结构 # 保持模块功能单一 # 编写清晰的文档和注释