目录

一、模块:组织代码的基本单元

1.1 什么是模块?

1.2 导入模块的多种方式

1.3 模块搜索路径

1.4 模块的缓存与重新加载

二、包:组织模块的命名空间

2.1 什么是包?

2.2 创建和使用包

2.3 __init__.py 的作用

三、相对导入与绝对导入

3.1 绝对导入

3.2 相对导入

四、将模块设计为可执行脚本

五、搭建你的代码库:

5.1 项目结构推荐

5.2 使用 __all__ 控制公开接口

5.3 避免循环导入

5.4 使用 if __name__ == "__main__" 进行模块自测

六、包的发布与安装

6.1 创建可安装的包

使用 setuptools 编写 setup.py:

6.2 本地安装

6.3 上传到 PyPI

七、常见问题与技巧

7.1 ImportError 和 ModuleNotFoundError

7.2 动态导入

7.3 查看模块文档

八、总结

随着项目规模的增长,将代码组织成模块和包是保持代码可维护性的关键。Python 通过模块和包机制,让你可以轻松复用代码、避免命名冲突,并构建清晰的代码结构。本文将系统讲解模块与包的概念、创建方法、导入技巧以及最佳实践,助你搭建属于自己的高效代码库。

一、模块:组织代码的基本单元

1.1 什么是模块?

模块是一个包含 Python 代码的 .py 文件。文件名就是模块名(去掉 .py 后缀)。模块可以定义函数、类、变量,也可以包含可执行代码。

python
# my_module.py
def greet(name):
    return f"Hello, {name}!"

PI = 3.14159

1.2 导入模块的多种方式

方式一:import 模块名

python
import my_module
print(my_module.greet("Alice"))
print(my_module.PI)

方式二:from 模块名 import 具体内容

python
from my_module import greet, PI
print(greet("Bob"))
print(PI)

方式三:from 模块名 import *(不推荐,易污染命名空间)

python
from my_module import *
print(greet("Charlie"))

方式四:给模块或导入内容起别名

python
import my_module as mm
from my_module import greet as g

1.3 模块搜索路径

当导入模块时,Python 按以下顺序搜索:
1. 当前脚本所在目录
2. PYTHONPATH 环境变量中的路径
3. Python 标准库路径
4. 第三方库安装路径(site-packages)

可以通过 sys.path 查看搜索路径:

python
import sys
print(sys.path)

1.4 模块的缓存与重新加载

模块在第一次导入后会被缓存到 sys.modules,再次导入直接使用缓存。如需重新加载,可使用 importlib.reload()。

python
import importlib
import my_module
importlib.reload(my_module)

二、包:组织模块的命名空间

2.1 什么是包?

包是一种通过点式模块名组织 Python 模块的方式。一个包就是一个包含 __init__.py 文件的目录(Python 3.3+ 中 __init__.py 可以省略,但建议保留以兼容旧版本)。

典型结构:
my_package/
    __init__.py
    module_a.py
    module_b.py
    sub_package/
        __init__.py
        module_c.py

2.2 创建和使用包

步骤 1:创建包目录,并添加 __init__.py(可以为空文件)。
步骤 2:编写模块文件。示例:

python
# my_package/module_a.py
def func_a():
    return "A"

# my_package/module_b.py
def func_b():
    return "B"

步骤 3:导入包中的模块。

python
# 方式1:导入整个模块
import my_package.module_a
print(my_package.module_a.func_a())

# 方式2:从包中导入模块
from my_package import module_b
print(module_b.func_b())

# 方式3:直接导入函数
from my_package.module_a import func_a
print(func_a())

2.3 __init__.py 的作用


1.标识目录为包(Python 3.3+ 可选,但建议保留)。
2.执行包的初始化代码。
3.控制 from package import * 的行为(通过 __all__)。
4.导入包内的子模块,方便外部调用。

示例:

python
# my_package/__init__.py
__all__ = ['module_a']   # 控制 from my_package import * 只导入 module_a
from .module_a import func_a   # 将 func_a 提升到包级别

外部调用时:

python
import my_package
my_package.func_a()   # 直接调用,无需写 my_package.module_a.func_a

三、相对导入与绝对导入

3.1 绝对导入

从项目的根目录或 sys.path 中的路径开始导入,适用于顶层脚本和包的任意位置。

python
# 在 my_package/sub_package/module_c.py 中
from my_package.module_a import func_a

3.2 相对导入

使用点号 . 表示当前目录,.. 表示上级目录,仅适用于包内部的模块(不能用于顶层脚本)。

python
# 在 my_package/sub_package/module_c.py 中
from ..module_a import func_a   # 导入上级目录的 module_a
from . import module_c          # 导入当前包内的 module_c

注意:直接运行的脚本(python script.py)不支持相对导入,因为它不在包中。

四、将模块设计为可执行脚本

每个模块都可以包含一个 if __name__ == "__main__": 块,使模块既可以作为库导入,又可以作为脚本独立运行。

python
# calculator.py
def add(a, b):
    return a + b

def sub(a, b):
    return a - b

if __name__ == "__main__":
    # 测试代码
    print(add(3, 5))
    print(sub(10, 4))

当直接运行 python calculator.py 时,测试代码执行;当在其他模块中 import calculator 时,测试代码不执行。

五、搭建你的代码库:

5.1 项目结构推荐


my_project/
    README.md
    requirements.txt
    setup.py
    my_lib/
        __init__.py
        core.py
        utils.py
        io/
            __init__.py
            file_handlers.py
        models/
            __init__.py
            user.py
    tests/
        test_core.py
        test_utils.py
    scripts/
        run.py

5.2 使用 __all__ 控制公开接口

在每个模块的顶部定义 __all__ 列表,明确哪些内容被 from module import * 导入,同时也作为公共 API 的文档。

python
# my_lib/core.py
__all__ = ['process_data', 'validate_input']

def process_data():
    pass

def validate_input():
    pass

def _internal_helper():   # 以下划线开头,约定私有
    pass

5.3 避免循环导入

循环导入指两个模块相互导入对方。解决方法:
1.重新设计代码结构,将共享内容提取到第三个模块。
2.将导入语句移到函数内部(延迟导入)。
3.使用 import 而不是 from ... import ...。

python
# 延迟导入示例
def func():
    from other_module import something
    something()

5.4 使用 if __name__ == "__main__" 进行模块自测

每个模块都可以包含简单的自测代码,便于独立验证功能。

六、包的发布与安装

6.1 创建可安装的包

使用 setuptools 编写 setup.py:

python
# setup.py
from setuptools import setup, find_packages

setup(
    name="my_lib",
    version="0.1.0",
    packages=find_packages(),
    install_requires=[
        "requests>=2.25.0",
    ],
    author="Your Name",
    description="A sample library",
)

6.2 本地安装


pip install -e 

-e 表示可编辑模式,修改代码后立即生效。

6.3 上传到 PyPI

通过 twine 上传到 Python 包索引,供用户安装。

bash
python setup.py sdist bdist_wheel
twine upload dist/*

七、常见问题与技巧

7.1 ImportError 和 ModuleNotFoundError

1.检查模块是否在 sys.path 中
2.确认包目录包含 __init__.py
3.检查循环导入

7.2 动态导入

使用 importlib.import_module() 实现动态导入。

python
import importlib
module_name = "math"
math = importlib.import_module(module_name)
print(math.sqrt(9))

7.3 查看模块文档

使用 help(module) 或 module.__doc__ 查看模块的文档字符串。

八、总结


单个模块: .py 文件,封装代码 
包*: 包含 __init__.py 的目录,组织模块 
导入方式 :import, from ... import, as 别名 
相对导入: 使用 . 和 ..,仅包内可用 
__name__:__main__ 表示直接运行 
__all__ :控制 from module import *的行为 
__init__.py: 包初始化、导入提升 
避免循环导入:重构、延迟导入 

希望本文能帮助你搭建属于自己的 Python 代码库。如果有任何疑问或经验分享,欢迎在评论区交流!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐