528 lines
12 KiB
Python
528 lines
12 KiB
Python
# 概述
|
||
# 模块和包是 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
|
||
|
||
# 项目组织
|
||
# 合理使用包和模块
|
||
# 避免过深的嵌套结构
|
||
# 保持模块功能单一
|
||
# 编写清晰的文档和注释 |