Skip to content

模块与包

模块和包是 Python 组织代码的基本方式。

模块基础

什么是模块

一个 .py 文件就是一个模块,模块可以包含函数、类、变量等。

python
# mymodule.py
"""这是一个示例模块"""

PI = 3.14159

def greet(name):
    """问候函数"""
    return f"Hello, {name}!"

class Person:
    """人员类"""
    def __init__(self, name):
        self.name = name

if __name__ == "__main__":
    # 模块作为脚本运行时执行
    print(greet("World"))

导入模块

python
# 导入整个模块
import math
print(math.pi)
print(math.sqrt(16))

# 导入模块并起别名
import numpy as np
import pandas as pd

# 导入特定内容
from math import pi, sqrt
print(pi)
print(sqrt(16))

# 导入并起别名
from math import sqrt as square_root

# 导入所有内容(不推荐)
from math import *
print(pi)
print(sin(0))

# 导入模块中的类
from mymodule import Person
p = Person("张三")

模块搜索路径

python
import sys

# 模块搜索路径
print(sys.path)

# 添加搜索路径
sys.path.append("/path/to/module")

# 查看模块位置
import math
print(math.__file__)

模块属性

python
import mymodule

# 模块名
print(mymodule.__name__)

# 模块文档
print(mymodule.__doc__)

# 模块文件路径
print(mymodule.__file__)

# 模块的所有属性
print(dir(mymodule))

# 模块的包名
print(mymodule.__package__)

__name__ 变量

python
# mymodule.py
def main():
    print("主程序")

if __name__ == "__main__":
    # 直接运行模块时执行
    main()
else:
    # 被导入时不执行
    pass

# 运行方式:
# python mymodule.py  -> __name__ == "__main__"
# import mymodule     -> __name__ == "mymodule"

什么是包

包是包含 __init__.py 文件的目录,用于组织模块。

mypackage/
├── __init__.py
├── module1.py
├── module2.py
└── subpackage/
    ├── __init__.py
    └── module3.py

创建包

python
# mypackage/__init__.py
"""我的包"""

__version__ = "1.0.0"

# 导入子模块
from .module1 import func1
from .module2 import func2

# mypackage/module1.py
def func1():
    return "Function 1"

# mypackage/module2.py
def func2():
    return "Function 2"

导入包

python
# 导入包
import mypackage

# 导入包中的模块
import mypackage.module1
mypackage.module1.func1()

# 导入包中的模块
from mypackage import module1
module1.func1()

# 导入包中的函数
from mypackage.module1 import func1
func1()

# 导入子包
from mypackage.subpackage import module3

# 导入包中所有模块(需要在 __init__.py 中定义 __all__)
from mypackage import *

__init__.py 文件

python
# mypackage/__init__.py

# 包初始化代码
print("包被导入")

# 定义 __all__ 控制 from package import *
__all__ = ["module1", "module2"]

# 导入常用内容
from .module1 import func1
from .module2 import func2

# 定义包级别变量
__version__ = "1.0.0"
__author__ = "Your Name"

相对导入和绝对导入

python
# 绝对导入(推荐)
from mypackage.module1 import func1
from mypackage.subpackage.module3 import func3

# 相对导入(在包内部使用)
# . 当前目录
# .. 上级目录
# ... 上上级目录

# module1.py 中
from .module2 import func2      # 同级模块
from .subpackage.module3 import func3  # 子包模块

# subpackage/module3.py 中
from ..module1 import func1     # 上级模块
from .. import module2          # 上级包的模块

模块高级特性

模块重载

python
import importlib
import mymodule

# 重载模块
importlib.reload(mymodule)

动态导入

python
import importlib

# 动态导入模块
module_name = "math"
module = importlib.import_module(module_name)
print(module.pi)

# 动态导入子模块
submodule = importlib.import_module("mypackage.module1")

模块作为命名空间

python
# config.py
DATABASE = {
    "host": "localhost",
    "port": 3306,
    "name": "mydb"
}

DEBUG = True

# main.py
import config

print(config.DATABASE["host"])
config.DEBUG = False

标准库模块

os 模块

python
import os

# 环境变量
print(os.environ.get("HOME"))
os.environ["MY_VAR"] = "value"

# 目录操作
os.getcwd()           # 当前目录
os.chdir("/path")     # 改变目录
os.mkdir("dir")       # 创建目录
os.makedirs("a/b/c")  # 创建多级目录

# 文件操作
os.remove("file.txt") # 删除文件
os.rename("old", "new")  # 重命名

# 路径操作
os.path.exists("file.txt")
os.path.isfile("file.txt")
os.path.isdir("dir")
os.path.join("a", "b", "c")

sys 模块

python
import sys

# 命令行参数
print(sys.argv)  # 脚本名和参数列表

# 模块搜索路径
print(sys.path)

# Python 版本
print(sys.version)
print(sys.version_info)

# 平台信息
print(sys.platform)

# 标准输入输出
sys.stdout.write("Hello\n")
sys.stderr.write("Error\n")

# 退出程序
# sys.exit(0)

pathlib 模块

python
from pathlib import Path

# 创建路径对象
p = Path(".")
p = Path("D:/projects")

# 路径操作
p / "subdir" / "file.txt"
p.parent
p.name
p.suffix
p.stem

# 文件操作
p.exists()
p.is_file()
p.is_dir()
p.mkdir(parents=True, exist_ok=True)
p.touch()  # 创建文件
p.unlink()  # 删除文件

# 读写文件
p.read_text(encoding="utf-8")
p.write_text("content", encoding="utf-8")

# 遍历
list(p.iterdir())
list(p.glob("*.py"))
list(p.rglob("*.py"))

datetime 模块

python
from datetime import datetime, date, time, timedelta

# 当前时间
now = datetime.now()
today = date.today()

# 创建日期时间
d = date(2024, 1, 15)
t = time(10, 30, 45)
dt = datetime(2024, 1, 15, 10, 30, 45)

# 格式化
print(now.strftime("%Y-%m-%d %H:%M:%S"))
print(now.isoformat())

# 解析
dt = datetime.strptime("2024-01-15", "%Y-%m-%d")

# 时间运算
tomorrow = today + timedelta(days=1)
next_week = today + timedelta(weeks=1)

# 时间差
delta = datetime(2024, 12, 31) - datetime.now()
print(delta.days)

json 模块

python
import json

# 编码
data = {"name": "张三", "age": 25}
json_str = json.dumps(data, ensure_ascii=False, indent=2)

# 解码
parsed = json.loads(json_str)

# 文件操作
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

with open("data.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)

random 模块

python
import random

# 随机数
random.random()           # 0-1 随机浮点数
random.randint(1, 100)    # 1-100 随机整数
random.uniform(1, 10)     # 1-10 随机浮点数

# 随机选择
items = ["a", "b", "c", "d"]
random.choice(items)      # 随机选一个
random.choices(items, k=3)  # 随机选多个(可重复)
random.sample(items, 2)   # 随机选多个(不重复)

# 打乱顺序
random.shuffle(items)

# 随机种子
random.seed(42)  # 设置种子,结果可复现

collections 模块

python
from collections import Counter, defaultdict, OrderedDict, namedtuple, deque

# Counter - 计数器
c = Counter("hello world")
print(c.most_common(2))  # [('l', 3), ('o', 2)]

# defaultdict - 默认字典
d = defaultdict(list)
d["key"].append("value")

# OrderedDict - 有序字典
od = OrderedDict()
od["a"] = 1
od["b"] = 2

# namedtuple - 命名元组
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y)

# deque - 双端队列
dq = deque([1, 2, 3])
dq.appendleft(0)
dq.pop()

itertools 模块

python
import itertools

# 无限迭代器
itertools.count(0, 2)      # 0, 2, 4, 6, ...
itertools.cycle("ABC")     # A, B, C, A, B, C, ...
itertools.repeat(10, 3)    # 10, 10, 10

# 排列组合
list(itertools.permutations([1, 2, 3], 2))  # 排列
list(itertools.combinations([1, 2, 3], 2))  # 组合
list(itertools.product([1, 2], [3, 4]))     # 笛卡尔积

# 链式操作
list(itertools.chain([1, 2], [3, 4]))  # [1, 2, 3, 4]
list(itertools.islice(range(10), 2, 7))  # [2, 3, 4, 5, 6]

# 分组
data = [("a", 1), ("a", 2), ("b", 1), ("b", 2)]
for key, group in itertools.groupby(data, lambda x: x[0]):
    print(key, list(group))

创建可安装的包

项目结构

mypackage/
├── setup.py
├── README.md
├── requirements.txt
├── mypackage/
│   ├── __init__.py
│   ├── module1.py
│   └── module2.py
└── tests/
    ├── __init__.py
    └── test_module1.py

setup.py

python
from setuptools import setup, find_packages

setup(
    name="mypackage",
    version="1.0.0",
    author="Your Name",
    author_email="your@email.com",
    description="A sample package",
    long_description=open("README.md").read(),
    url="https://github.com/yourname/mypackage",
    packages=find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires=">=3.6",
    install_requires=[
        "requests>=2.25.0",
    ],
)

安装包

bash
# 开发模式安装
pip install -e .

# 正常安装
pip install .

# 上传到 PyPI
python setup.py sdist upload

实践示例

配置管理模块

python
# config.py
"""配置管理模块"""
import json
from pathlib import Path
from typing import Any, Dict

class Config:
    """配置管理类"""

    _instance = None
    _config = {}

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def load(self, config_file: str):
        """加载配置文件"""
        path = Path(config_file)
        if path.exists():
            with open(path, "r", encoding="utf-8") as f:
                self._config = json.load(f)

    def get(self, key: str, default: Any = None) -> Any:
        """获取配置值"""
        keys = key.split(".")
        value = self._config
        for k in keys:
            if isinstance(value, dict):
                value = value.get(k)
            else:
                return default
        return value if value is not None else default

    def set(self, key: str, value: Any):
        """设置配置值"""
        keys = key.split(".")
        config = self._config
        for k in keys[:-1]:
            config = config.setdefault(k, {})
        config[keys[-1]] = value

    def save(self, config_file: str):
        """保存配置文件"""
        with open(config_file, "w", encoding="utf-8") as f:
            json.dump(self._config, f, indent=2, ensure_ascii=False)

# 使用
config = Config()
config.load("config.json")
print(config.get("database.host"))
config.set("app.debug", True)
config.save("config.json")

插件系统

python
# plugins/__init__.py
"""插件系统"""
import importlib
from pathlib import Path
from typing import Dict, Type

class PluginBase:
    """插件基类"""

    name = "base"

    def execute(self, *args, **kwargs):
        """执行插件"""
        raise NotImplementedError

class PluginManager:
    """插件管理器"""

    def __init__(self):
        self._plugins: Dict[str, Type[PluginBase]] = {}

    def register(self, plugin_class: Type[PluginBase]):
        """注册插件"""
        self._plugins[plugin_class.name] = plugin_class

    def load_from_directory(self, directory: str):
        """从目录加载插件"""
        plugin_dir = Path(directory)
        for file_path in plugin_dir.glob("*.py"):
            if file_path.name.startswith("_"):
                continue

            module_name = file_path.stem
            spec = importlib.util.spec_from_file_location(
                f"plugins.{module_name}", file_path
            )
            module = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(module)

            for attr_name in dir(module):
                attr = getattr(module, attr_name)
                if (isinstance(attr, type) and
                    issubclass(attr, PluginBase) and
                    attr != PluginBase):
                    self.register(attr)

    def get_plugin(self, name: str) -> PluginBase:
        """获取插件实例"""
        plugin_class = self._plugins.get(name)
        if plugin_class:
            return plugin_class()
        raise ValueError(f"Plugin not found: {name}")

    def execute(self, name: str, *args, **kwargs):
        """执行插件"""
        plugin = self.get_plugin(name)
        return plugin.execute(*args, **kwargs)

# 使用
manager = PluginManager()
manager.load_from_directory("plugins")
result = manager.execute("my_plugin", data="test")