小白学 Python
AI 编程指南GitHub
© 2026 小白学 Python · 基于 walter201230/Python 教程
课程目录关于本站联系方式隐私政策GitHub

模块

完整讲解 · 6 段教学·配 4 道练习题·预计 35 分钟

本页是本章的通读版,可直接读完全部讲解。想动手写代码、跑判分,去 闯关模式。

教学 01 / 06

第八节:模块

到这一节,Python 基础学习就接近尾声了。

这一节学的是 模块——把代码按功能切分、复用别人写好的代码的关键工具。

本节脉络

  • 一、Python 模块简介
  • 二、模块的使用:import / from···import / from ··· import *
  • 三、主模块和非主模块(__name__ == '__main__')
  • 四、包(Package)
  • 五、作用域(public / private)

提示:本节的练习全部使用 Python 内置标准库(math / random / datetime / json 等),不会让你创建额外的 .py 文件。

教学 02 / 06

一、Python 模块简介

随着代码越写越多,把所有代码都堆到一个文件里会越来越难维护。

之前我们学过:

  • 函数:把一段功能封装起来,方便重复使用
  • 类:把相关的变量和函数封装到一起

而 模块 比类更高一级——一个模块里可以放变量、函数、类。

┌─────────────────────┐
│ 模块                 │
│                     │
│  变量                │
│                     │
│  函数                │
│                     │
│  ┌────────────────┐ │
│  │ 类              │ │
│  │   变量1/变量2... │ │
│  │   函数1/函数2... │ │
│  └────────────────┘ │
└─────────────────────┘

封装函数用 def,封装类用 class,封装模块不需要任何关键字——

在 Python 中,一个 .py 文件就是一个模块(Module)。

为什么要用模块?

  1. 提高可维护性——按功能拆分到不同文件,不再是一个巨型脚本
  2. 代码复用——别人写好的模块可以直接拿来用,不必从零造轮子
  3. 避免命名冲突——相同名字的函数和变量可以分别存在不同模块中

Python 自带了很多非常有用的模块(叫 标准库),装好 Python 就能用,比如 math、random、datetime、json、os、sys ……

模块大致分两类:

  • 标准库模块:Python 自带,比如 math
  • 自定义模块:你自己写的 .py 文件
  • 第三方模块:别人发布到 PyPI 上、用 pip install 安装的

本节练习主要用标准库。

教学 03 / 06

二、模块的使用

要使用某个模块,必须先 导入。导入的关键字是 import。

1、import

最基本的语法:

python到闯关页运行这段 →
import 模块名

也可以一次导入多个:

python到闯关页运行这段 →
import module1, module2, module3

例子——使用标准库 math 模块的 pi 属性:

python到闯关页运行这段 →
import math

print(math.pi)

输出:

3.141592653589793

一个模块只会被导入一次,不管你写了多少次 import。重复 import 不会重复执行模块代码。

2、from ··· import

import math 只是把 math 这个模块整体引进来,使用里面的东西必须写前缀(math.pi、math.sqrt(...))。

如果只想用模块里的某一个函数或属性,可以直接 挑出来导入:

python到闯关页运行这段 →
from 模块名 import 名字1, 名字2, ...

对比一下:

python到闯关页运行这段 →
# 写法 1:import 整个模块
import math
print(math.pi)        # 必须写 math. 前缀

# 写法 2:from···import 直接拎出来
from math import pi
print(pi)             # 不用写 math.

两种都可以,看场景:

  • 用得多 / 怕重名 → import math
  • 只用一两个、想少打字 → from math import pi, sqrt

3、from ··· import *

如果想把模块里 所有公开 的名字一次性全部拉进当前命名空间:

python到闯关页运行这段 →
from math import *

print(pi)
print(sqrt(16))

⚠️ 不推荐这么写。会把一堆名字塞进当前作用域,容易和你自己定义的变量名冲突,代码也变得不清晰。除非交互式探索,正式代码里基本不用。

4、起别名(as)

模块名太长?可以起别名:

python到闯关页运行这段 →
import datetime as dt

today = dt.date(2026, 1, 1)
print(today)

数据科学圈最常见的两个:

python到闯关页运行这段 →
import numpy as np
import pandas as pd
练习 1 / 4用 math 模块算圆周长去闯关页做这题 →练习 2 / 4from···import:直接拎出 sqrt去闯关页做这题 →
教学 04 / 06

三、主模块和非主模块

1、定义

  • 主模块:被 直接运行 的那个 .py 文件
  • 非主模块:被别的模块 import 进来的那个

类比:你 python a.py,a 就是主模块;a.py 里如果 import b,b 就是非主模块。

2、__name__ 属性

怎么在代码里判断 当前模块到底是被直接运行还是被别人 import 的?

Python 给每个模块都设置了一个特殊变量 __name__:

  • 模块被 直接运行 时,__name__ 的值就是字符串 '__main__'
  • 模块被 import 时,__name__ 的值就是模块名本身(比如 'mymod')

所以经典写法是:

python到闯关页运行这段 →
# mymod.py

def main():
    print('正在运行 main 逻辑')

if __name__ == '__main__':
    main()

效果:

  • 直接 python mymod.py → 打印 正在运行 main 逻辑
  • 别的文件 import mymod → 不会自动跑 main(),函数依然可以被调用

这是 Python 中最常见的一段「魔法咒语」。它的意义是:写一个模块时,既能让它当库被别人 import,又能让它能直接被运行做测试或当脚本用。

3、为什么要这么写?

不写 if __name__ == '__main__': 守卫的话,模块里所有顶层代码 都会在被 import 时执行——往往不是你想要的。

python到闯关页运行这段 →
# bad_mymod.py
def add(a, b):
    return a + b

print(add(1, 2))   # 这一行会在被 import 时立刻执行
python到闯关页运行这段 →
# 别的文件
import bad_mymod   # 副作用:屏幕上立刻打印了 3

加上 if __name__ == '__main__': 包裹后,这个 print(add(1, 2)) 就只在直接运行时执行,被 import 时不会触发。

教学 05 / 06

四、包(Package)和作用域

1、什么是包

模块多了,难免会出现重名——你写了一个 utils.py,别人也写了一个 utils.py,怎么办?

Python 的解决方案是 包(Package):用 目录 来组织模块,不同目录下可以有同名模块。

一个典型的包结构:

myproject/
└── com/
    └── learn/
        └── module/
            ├── __init__.py
            └── lname.py     ← 完整名是 com.learn.module.lname

注意每个目录里都有一个 __init__.py:

这个文件 必须存在(哪怕是空的),Python 才会把这个目录当成包,而不是普通目录。

__init__.py 本身也是一个模块——它对应的模块名就是 包名本身。

导入包里的模块时,用点号一层层进去:

python到闯关页运行这段 →
import com.learn.module.lname
from com.learn.module import lname
from com.learn.module.lname import some_func

现代 Python(3.3+)也支持 命名空间包——不强制要求 __init__.py。但传统包结构仍然最常见,初学阶段记住「目录里要有 __init__.py」就够了。

2、作用域:public vs private

学过 Java / C++ 的同学知道,类成员可以标 public / private。

Python 没有真正的访问控制关键字,但有一套约定俗成的命名规则:

命名含义例子
abc / MyClass公开(public),任何地方都可以用普通函数、变量
_abc「内部使用」(约定),外部 不应该 直接引用内部辅助函数
__abc名字改写(name mangling),主要用于类内部类的私有属性
__abc__特殊变量 / 魔法方法__name__、__init__

举例:

python到闯关页运行这段 →
def _diamond_vip(lv):
    print('尊敬的钻石会员用户,您好')
    return f'DiamondVIP{lv}'


def _gold_vip(lv):
    print('尊敬的黄金会员用户,您好')
    return f'GoldVIP{lv}'


def vip_lv_name(lv):
    """对外公开的入口"""
    if lv == 1:
        print(_gold_vip(lv))
    elif lv == 2:
        print(_diamond_vip(lv))


vip_lv_name(2)

输出:

尊敬的钻石会员用户,您好
DiamondVIP2

vip_lv_name 是公开的(外部调用入口),_diamond_vip / _gold_vip 名字带下划线——告诉别人「这是我内部用的辅助函数,别去依赖它」。

⚠️ Python 不会真的阻止你访问 _xxx,只是 大家约定 不要这么干。代码就像城市的红绿灯,靠协作而不是栏杆。

教学 06 / 06

五、几个常用的标准库

下面这几个是日常开发里 超高频 出现的标准库模块,先认识一下,下面几道练习也会用到。

1、math —— 数学函数

python到闯关页运行这段 →
import math

print(math.pi)          # 圆周率 3.141592653589793
print(math.e)           # 自然常数 e
print(math.sqrt(16))    # 平方根 → 4.0
print(math.floor(3.7))  # 向下取整 → 3
print(math.ceil(3.2))   # 向上取整 → 4

2、random —— 随机数

python到闯关页运行这段 →
import random

random.seed(42)              # 固定随机种子,结果可复现
print(random.randint(1, 10)) # 1-10 之间的随机整数(含两端)
print(random.choice(['A', 'B', 'C']))  # 随机选一个

在练习里我们会用 random.seed(...) 固定结果——这样判分时输出就稳定了。

3、datetime —— 日期与时间

python到闯关页运行这段 →
from datetime import date, datetime

d = date(2026, 1, 1)
print(d.year, d.month, d.day)  # 2026 1 1

now = datetime(2026, 1, 1, 12, 30, 0)
print(now)                     # 2026-01-01 12:30:00

4、json —— JSON 序列化

把 Python 字典 / 列表 转成 JSON 字符串:

python到闯关页运行这段 →
import json

data = {'name': 'Alice', 'age': 18}
print(json.dumps(data))

输出:

{"name": "Alice", "age": 18}

反过来——把 JSON 字符串解析回 Python 对象:

python到闯关页运行这段 →
import json

s = '{"name": "Alice", "age": 18}'
obj = json.loads(s)
print(obj['name'])   # Alice

下面来动手练几道。每道题都需要你 使用 import 语句 引入对应的标准库。

练习 3 / 4用 datetime 模块构造日期去闯关页做这题 →练习 4 / 4用 json 模块序列化字典去闯关页做这题 →

读完了?动手练一遍才算真会。

去闯关模式练习 →