第六章 · 模块与包

import 机制

本节目标

学完这一节,你会知道:

  1. 什么是模块,什么是包
  2. import 有哪些常见写法
  3. 如何创建自己的模块
  4. if __name__ == "__main__" 是什么
  5. 如何避免常见导入错误

当一个文件越来越长时,就需要把代码拆到多个文件里。import 就是把别的文件里的代码拿过来用。

先跑一个例子

在同一个文件夹里创建两个文件。

utils.py

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


def greet(name):
    return f"你好,{name}!"

main.py

from utils import add, greet

print(add(3, 5))
print(greet("小明"))

运行:

python3 main.py

你会看到:

8
你好,小明!

main.py 导入并使用了 utils.py 里的函数。

什么是模块?

一个 .py 文件就是一个模块。

project/
├── main.py
└── utils.py

这里 utils.py 就是一个模块。

Python 自带很多模块,比如:

import math
import random
import json

你自己写的 .py 文件也可以被导入。

import 的常见写法

导入整个模块:

import math

print(math.sqrt(16))

导入模块里的某个函数:

from math import sqrt

print(sqrt(16))

导入并起别名:

import datetime as dt

print(dt.datetime.now())

不推荐:

from math import *

它会把很多名字直接放进当前文件,容易看不出函数来自哪里。

创建自己的模块

calculator.py

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


def multiply(a, b):
    return a * b

main.py

import calculator

print(calculator.add(3, 5))
print(calculator.multiply(4, 6))

也可以:

from calculator import add, multiply

print(add(3, 5))
print(multiply(4, 6))

如果模块名比较清楚,import calculator 反而更容易读。

什么是包?

包就是包含多个模块的文件夹。

my_project/
├── main.py
└── tools/
    ├── __init__.py
    ├── file_utils.py
    └── string_utils.py

__init__.py 的文件夹通常可以当作包。

导入包里的模块:

from tools.file_utils import read_text
from tools.string_utils import clean_text

name 和 main

很多文件底部会写:

if __name__ == "__main__":
    print("直接运行这个文件时才执行")

它的作用是:区分“直接运行”和“被别人导入”。

例子:

utils.py

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


if __name__ == "__main__":
    print("测试 add 函数")
    print(add(1, 2))

直接运行:

python3 utils.py

测试代码会执行。

main.py 导入时,测试代码不会执行。

模块搜索路径

导入模块时,Python 会去一些地方找:

  1. 当前运行目录
  2. 标准库目录
  3. 第三方库目录
  4. 环境变量指定的目录

可以查看:

import sys

for path in sys.path:
    print(path)

刚入门时,最重要的是:自己写的模块最好和主程序放在清楚的项目结构里。

逐行拆解

再看开头的例子:

from utils import add, greet

utils.py 中导入 addgreet 两个函数。

print(add(3, 5))

调用导入的 add()

如果写成:

import utils

调用时就要写:

utils.add(3, 5)

自己改一改

继续扩展两个文件。

utils.py

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


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


def greet(name):
    return f"你好,{name}!"

main.py

import utils

print(utils.add(10, 3))
print(utils.subtract(10, 3))
print(utils.greet("马哥"))

然后继续改:

  1. 增加一个 multiply() 函数
  2. main.py 里调用它
  3. utils.py 加上 if __name__ == "__main__" 测试代码

常见错误

1. 文件名和标准库重名

不要把自己的文件命名为:

json.py
random.py
math.py
email.py

否则可能影响标准库导入。

2. 循环导入

a.py 导入 b.py,同时 b.py 又导入 a.py,可能造成循环导入。

解决思路:把共同代码放到第三个模块,或者重新整理依赖关系。

3. 被导入时执行了测试代码

把测试代码放进:

if __name__ == "__main__":
    ...

4. 路径结构混乱

如果导入失败,先确认文件是否在当前项目目录里,运行命令的位置是否正确。

小练习

练习 1:创建数学模块

创建 math_tools.py,里面写 add()multiply(),再在 main.py 中导入使用。

练习 2:字符串工具

创建 string_tools.py,写一个 clean_text(text),返回去掉空白并转小写的字符串。

练习 3:模块自测

math_tools.py 加上 if __name__ == "__main__",直接运行时打印测试结果。

参考答案

练习 1:

math_tools.py

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


def multiply(a, b):
    return a * b

main.py

from math_tools import add, multiply

print(add(1, 2))
print(multiply(3, 4))

练习 2:

def clean_text(text):
    return text.strip().lower()

练习 3:

if __name__ == "__main__":
    print(add(1, 2))
    print(multiply(3, 4))

小结

这一节你学会了:

  1. 一个 .py 文件就是一个模块
  2. import modulefrom module import name 是最常见导入方式
  3. 包可以把多个模块组织到文件夹里
  4. if __name__ == "__main__" 可以避免导入时执行测试代码
  5. 文件名不要和标准库重名

下一节我们会学习常用标准库。Python 自带很多模块,能直接帮你处理时间、随机数、数学、路径等任务。

代码拆成多个文件,项目就开始长大了

import 的意义,是让每个文件各司其职,而不是把所有代码都堆成一锅粥。先从 utils.py 和 main.py 练起就够了。马哥的小提醒:别给文件起名 random.py、json.py,不然标准库会有点委屈。

讨论 (0)

还没有评论,来抢沙发吧!