程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Python 基础

  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
      • 1. 模块 (Module)
        • 1.1 为什么使用模块?
        • 1.2 创建与使用模块
        • 1.3 import 语句
        • 1.4 from ... import 语句
        • 1.5 as 关键字:别名
        • 1.6 from ... import * 的行为
        • 1.7 控制 import * 的行为: __all__
        • 1.8 模块的缓存与重新加载
        • 1.9 模块的搜索路径
      • 2. 包 (Package)
        • 2.1 创建与组织包
        • 2.2 在包外部导入
        • 2.3 __init__.py 的妙用:提升成员
        • 2.4 包内导入:绝对与相对导入
      • 3. if __name__ == "__main__" 的作用
    • pip 包管理工具
  • Python
  • Python 进阶
scholar
2025-07-23
目录

模块与包

# Python 模块与包

随着程序规模的增长,将所有代码都放在一个文件中是不可行且难以维护的。Python 通过模块 (Modules) 和包 (Packages) 的机制来组织代码,使其结构清晰、易于复用和管理。


# 1. 模块 (Module)

在 Python 中,任何一个 .py 文件都可以被看作一个模块。模块中可以包含变量、函数、类等定义。通过将相关的代码组织在不同的模块中,我们可以实现代码的逻辑分离。

# 1.1 为什么使用模块?

  • 代码组织: 将复杂的代码分解成多个逻辑上独立的单元。
  • 可复用性: 一个模块可以被多个不同的程序导入和使用。
  • 命名空间: 每个模块都有自己的命名空间,可以有效避免不同模块间的命名冲突。

# 1.2 创建与使用模块

假设我们有一个 my_math.py 文件:

# my_math.py

PI = 3.14159

def add(a, b):
    """返回两数之和"""
    return a + b

class Circle:
    """圆形类"""
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return PI * self.radius * self.radius
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

现在,我们可以在另一个文件 main.py 中使用这个模块。

# 1.3 import 语句

这是最直接的导入方式,它会导入整个模块。

# main.py
import my_math

# 使用时需要通过 "模块名.成员" 的方式访问
print(f"PI 的值: {my_math.PI}")
circle = my_math.Circle(10)
print(f"半径为10的圆面积: {circle.area()}")
1
2
3
4
5
6
7

# 1.4 from ... import 语句

如果你只想从模块中导入特定的成员,可以使用 from...import。

# main.py
from my_math import PI, add

# 可以直接使用导入的成员,无需模块名前缀
print(f"PI 的值: {PI}")
print(f"5 + 3 = {add(5, 3)}")
1
2
3
4
5
6

# 1.5 as 关键字:别名

当模块名很长或者你想避免命名冲突时,可以使用 as 来给导入的模块或成员起一个别名。

import my_math as m
from my_math import Circle as C

print(f"PI: {m.PI}")
my_circle = C(5)
1
2
3
4
5

# 1.6 from ... import * 的行为

使用 * 可以导入模块中所有不以下划线 _ 开头的公开名称。

from my_math import * 

# PI, add, Circle 都可以直接使用
print(PI)
1
2
3
4

警告:通常不推荐在代码中使用 from module import *,因为它会将所有导入的名称直接放入当前命名空间,很容易导致意想不到的命名冲突,降低代码的可读性。

# 1.7 控制 import * 的行为: __all__

你可以在模块中定义一个名为 __all__ 的列表,来明确指定当使用 from my_module import * 时,哪些名称应该被导入。

# my_math_pro.py

__all__ = ['add', 'PI'] # 只希望外部通过 * 导入 add 和 PI

PI = 3.14159
_INTERNAL_CONSTANT = 9.8 # 以下划线开头,默认不会被 * 导入

def add(a, b):
    return a + b

class Circle: # Circle 没有在 __all__ 中
    pass
1
2
3
4
5
6
7
8
9
10
11
12
# main.py
from my_math_pro import *

print(add(1, 2)) # 正常
print(PI)        # 正常
# c = Circle()   # NameError: name 'Circle' is not defined
1
2
3
4
5
6

# 1.8 模块的缓存与重新加载

为了提高效率,Python 会缓存已经导入的模块。当你第二次 import 同一个模块时,Python 不会再次执行模块文件,而是直接从缓存(sys.modules)中获取。

这在开发和调试时可能会带来问题。如果你修改了模块的代码,需要重新加载它才能看到变化。可以使用 importlib 模块来实现。

import my_math
import importlib

# ... 假设你在这里修改了 my_math.py 的源文件 ...

# 重新加载模块
importlib.reload(my_math) 
1
2
3
4
5
6
7

# 1.9 模块的搜索路径

当你 import 一个模块时,Python 解释器会按照以下顺序在 sys.path 列表中指定的目录里搜索它:

  1. 当前目录: 运行主程序的脚本所在的目录。
  2. PYTHONPATH 环境变量: 一个包含目录列表的环境变量,可以手动设置。
  3. 标准库目录: Python 安装时自带的库所在的目录。
import sys
print(sys.path)
1
2

# 2. 包 (Package)

当项目变得更大,拥有大量模块时,我们可以使用包来进一步组织它们。

包就是一个包含 __init__.py 文件的目录。这个目录里可以存放其他的模块文件或子包。

  • __init__.py 文件的作用:
    • 标识目录为包: 它的存在告诉 Python 这个目录应该被当作一个包来对待。在现代Python(3.3+)中,即使没有 __init__.py 文件,目录也可以被当作“命名空间包”导入,但为了兼容性和清晰性,创建它是最佳实践。
    • 初始化包: 当包被导入时,__init__.py 文件会被自动执行。你可以在这里进行包级别的初始化操作,或者定义包的 __all__ 变量。

# 2.1 创建与组织包

假设我们有如下的目录结构:

my_project/
├── main.py
└── my_app/
    ├── __init__.py
    ├── api.py
    └── models/
        ├── __init__.py
        └── user.py
1
2
3
4
5
6
7
8
  • my_app 是一个顶级包。
  • models 是 my_app 的一个子包。
  • api.py 和 user.py 是模块。

# 2.2 在包外部导入

在 main.py 中,我们可以这样导入包中的模块:

# main.py

# 导入 my_app 包中的 api 模块
import my_app.api
my_app.api.call_api()

# 导入 user 模块,并起别名
from my_app.models import user as user_model
db_user = user_model.User("Alice")
1
2
3
4
5
6
7
8
9

# 2.3 __init__.py 的妙用:提升成员

你可以在 __init__.py 中将包内深层次的成员提升到包的顶层,方便外部调用。

# 在 my_app/models/__init__.py 中写入:
from .user import User

# 那么在 main.py 中就可以这样导入,显得更简洁:
from my_app.models import User # 而不是 from my_app.models.user import User
user_instance = User("Bob")
1
2
3
4
5
6

# 2.4 包内导入:绝对与相对导入

当你在一个包的内部,需要导入同包的其他模块时,有两种方式:

  • 绝对导入 (Absolute Import): 从项目的根目录(即包含main.py的my_project目录)开始,写出完整的路径。

    # 假设在 my_app/api.py 中,需要使用 User 模型
    from my_app.models.user import User # 绝对路径导入
    
    def get_user(id):
        # ...
        return User("test")
    
    1
    2
    3
    4
    5
    6

    优点: 路径清晰,明确,无论当前文件被移动到何处,导入路径都有效。 缺点: 如果顶层包名(my_app)改变,所有导入语句都需要修改。

  • 相对导入 (Relative Import): 使用 . 和 .. 来表示当前路径和父路径,只能在包内部使用。

    • . : 表示当前包(目录)。
    • ..: 表示上级包(目录)。
    # 假设在 my_app/api.py 中,需要使用同级目录下的 models 子包中的 user 模块
    from .models.user import User # .models 表示从当前包(my_app)寻找 models
    
    # 假设在 my_app/models/user.py 中,需要导入 my_app/api.py
    from ..api import get_user # `..` 表示 models 的上级目录,即 my_app
    
    1
    2
    3
    4
    5

    优点: 当整个包被重命名或移动时,内部引用不受影响。 缺点: 增加了路径的复杂性,过度使用 .. 会使代码难以理解。


# 3. if __name__ == "__main__" 的作用

这是一个非常常见的代码块,它的核心作用是:让一个模块既可以作为脚本被直接运行,也可以作为模块被其他程序导入。

  • 当一个 .py 文件被直接执行时 (例如 python my_module.py),Python 解释器会将其内置的 __name__ 变量设置为字符串 "__main__"。
  • 当一个 .py 文件被作为模块导入时 (import my_module),它的 __name__ 变量会被设置为模块自己的名字 (例如 "my_module")。
# my_math.py

PI = 3.14

def add(a, b):
    return a + b

def main_test():
    """包含测试或演示代码的函数"""
    print("--- 模块自测 ---")
    print(f"计算 5 + 10: {add(5, 10)}")
    print("--- 自测结束 ---")

# 检查这个文件是否被直接运行
if __name__ == "__main__":
    main_test()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • 运行 python my_math.py: __name__ 是 "__main__",所以 main_test() 函数会被调用,屏幕上会打印出演示信息。
  • 在其他文件中 import my_math: __name__ 是 "my_math",if 条件不满足,main_test() 函数不会被调用。这样,导入 my_math 只会得到 PI 和 add,而不会执行测试代码,非常干净。
编辑此页 (opens new window)
上次更新: 2025/07/23, 06:33:16
标准库精讲
pip 包管理工具

← 标准库精讲 pip 包管理工具→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式