跳到主要内容 Python 模块与包详解 | 极客日志
Python
Python 模块与包详解 Python 中模块和包的概念、区别及使用方法。涵盖标准库、自定义及第三方模块的分类,详细讲解了五种导入方式及其注意事项,包括命名冲突处理。阐述了主模块与__name__变量的作用机制,以及包的目录结构和__init__.py 文件的功能。最后简要说明了 pip 包管理器的安装、镜像配置及常用命令。
信号故障 发布于 2026/3/22 更新于 2026/4/18 11K 浏览Python 模块与包
包和模块是 Python 语言封装功能和组织程序集的解决方案,类似 Java 中的 package 和 C# 中的 namespace,将固定功能模块的代码聚合在一起,提高程序的复用性和可维护性。
1. 模块
每一个.py 文件都是一个模块,每个模块中可以包含变量、函数、类等内容。模块多用于封装固定功能的代码,每个模块都是一个工具,可以提升代码的可维护性和可复用性,还能避免命名冲突。
Python 中的模块分为三种:标准库模块、自定义模块和第三方模块。
标准库模块 :随着 Python 自带的一些模块,位于 Python 安装目录的\Lib 下(site-packages 中的除外)。有些是 C 语言实现的,不能看到源码;剩下是 Python 实现,可见源码。例如:copy, os, math, sys, time 等都是标准库模块。其中 math, sys, time 就是内置模块,copy, os 就是非内置模块。有些模块是用包进行组织的,包的概念后面会有介绍。Python 提供了标准库文档用于参考:https://docs.python.org/zh-cn/3/py-modindex.html
自定义模块 :是我们为了实现功能自己编写的模块。
第三方模块 :通常位于 Python 安装目录的\Lib\site-packages,引用别人写好的现成的功能,往往使用包来引入,通常使用 pip 进行管理。
1.1 定义模块
模块的命名要符合标识符的命名规则,模块名(文件名)大小写敏感,最重要的是不能与标准库模块重名,否则引入时,会被与之重名的标准库模块顶替(类似 Java 中的双亲委派)。
例如定义两个模块在根路径下,order 和 pay。
order.py
max_amount = 5000_0000
def create_order ():
print ('create_order' )
def cancel_order ():
print ('cancel_order' )
def info ():
print ('order info' )
pay.py
timeout = 300
def wechat_pay ():
print ('wechat_pay' )
def alipay_pay ():
print ('alipay_pay' )
def info ():
print ('pay info' )
1.2 引入模块
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
在根目录建一个新的 mytest 模块,引入刚刚建的两个模块,总共有 5 种常见的引入方式,在不同的场景使用适合的方式进行导入。
1.2.1 import 模块名 引入模块中的全部成员,要使用模块中的成员,需要用 模块名. 的方式访问。
import order
import pay
print (order.max_amount)
order.create_order()
order.cancel_order()
order.info()
print (pay.timeout)
pay.alipay_pay()
pay.wechat_pay()
pay.info()
1.2.2 import 模块名 as 别名 可以为引入的模块取一个别名,通过 别名. 访问,但是别名需要符合标识符的命名规范。
import order as o
import pay as p
print (o.max_amount)
o.create_order()
o.cancel_order()
o.info()
print (p.timeout)
p.alipay_pay()
p.wechat_pay()
p.info()
1.2.3 from 模块名 import 具体内容 1, 具体内容 2 … 之前的方式都是将整个模块引入,通过 from 模块名 import 具体内容,... 可以将模块中的部分成员引入,并可以不需经过模块,直接调用。
from order import max_amount, create_order, cancel_order, info
from pay import timeout, wechat_pay, alipay_pay, info
print (max_amount)
print (timeout)
create_order()
cancel_order()
alipay_pay()
wechat_pay()
info()
但是有一个问题,两个模块中有重名的成员时,后引入的会覆盖先引入的,例如上面程序运行结果就是:info() 执行的是 pay 模块中的 info()。
1.2.4 from 模块名 import 具体内容 1 as 别名 1, 具体内容 2 as 别名 2 … 在 3 的基础上,通过这种方式,将重名成员设置别名,避免冲突。
from order import info as o_info
from pay import info as p_info
o_info()
p_info()
1.2.5 from 模块名 import * 引入模块中全部成员,但是和第 1 种不同的是,访问成员不需要通过模块名或别名,同样会出现重名成员后者覆盖前者的情况,而且和当前模块中声明的成员也可能无形中发生冲突,同样存在按照前后顺序覆盖。
timeout = 0
from order import *
from pay import *
print (timeout)
print (max_amount)
alipay_pay()
wechat_pay()
create_order()
cancel_order()
info()
运行结果:timeout 被 pay.timeout 覆盖,order.max_amount 也会被 max_amount 覆盖,info() 调用的是 pay 模块中的 info()。
在 Python 中,可以通过 __all__ 来控制 from 模块名 import * 引入哪些成员,且 __all__ 仅针对 from 模块名 import * 的方式有效,__all__ 的值可以是列表或元组。
例如将 order.py 修改成以下,被引入时,只能引入 create_order, cancel_order 两个函数。
列表和元组中每个元素是字符串形式的属性名,不要把函数或变量等直接当成对象直接放进去
max_amount = 5000_0000
def create_order ():
print ('create_order' )
def cancel_order ():
print ('cancel_order' )
def info ():
print ('order info' )
__all__ = ['create_order' , 'cancel_order' ]
在 mytest.py 中再使用未引入的成员将报错。
from order import *
print (max_amount)
create_order()
cancel_order()
info()
Traceback (most recent call last):
File "D:\python-lang-test\test1\mytest.py", line 60, in <module>
print(max_amount)
NameError: name 'max_amount' is not defined
Process finished with exit code 1
1.3 主模块和 name 一个 Python 项目由诸多模块构成,如果一个模块,是直接在 Python 解释器后直接运行的,则这个模块就是主模块,类似 Java 中 JVM 从某个类的 public static void main(String[] args) 方法开始执行。
比如这样运行某个 Python 项目,mytest.py 模块就是主模块。
D:\python-lang-test\test1\.venv\Scripts\python.exe D:\python-lang-test\test1\mytest.py
Python 中有一个特殊的变量:__name__,是一个字符串类型,该变量只有在主模块中出现时,才会被 Python 解释器赋值为一个字符串:"main ",如果出现在了非主模块,则会被赋值为当前模块的名。
同时,Python 代码运行时,一旦执行了 import 语句,被引入的模块代码就会开始自然从上向下执行,类似浏览器中执行 JS 代码一样。
import son
print ('主模块执行 - 开始' )
print (__name__)
son.fun()
print ('son 模块执行 - 开始' )
def fun ():
print (__name__)
运行结果就是上面说的那样:son 模块 print 先执行了,然后主模块 print 后执行,而且 __name__ 被解释器自动赋上对应的值。
这样设计的用途是,可以对某个模块内自己实现的方法进行简单测试,类似 Java 中如果想在某个类中测试下刚刚写好的方法,就会随手就地写一个 main 方法然后 main 中直接启动自己写的方法,对 Python 而言,可以将某个子模块最后加上这样一段 if __name__ == '__main__' 逻辑。
print ('son 模块执行 - 开始' )
def fun ():
print ('hello world' )
if __name__ == '__main__' :
fun()
只要将当前模块直接启动,就能被当作主模块被解释器直接执行 if __name__ == '__main__' 下的逻辑实现临时测试,但是上线后当作为子模块被主模块引入,这段 if 逻辑则会被忽略。
如果不加这段 if 逻辑,同样可以进行测试,但是需要上线前删除或注释测试代码,一旦忘记了,或者少注释了一段,误上线后就可能造成很大的影响,因此 if __name__ == '__main__' 至少可以使得程序更加安全。
2. 包 Python 中,包并不是一个和模块并列的东西,而是模块的进一步升级,一个包含 __init__.py 文件的文件夹就叫做包。通常将实现某个近似或相关功能的众多模块放在一个包中。
__init__.py 是包的初始化文件,可以编写一些初始化逻辑(比如检查下当前环境等),还可以控制包被导入的内容,当包被导入时,__init__.py 将被自动调用。
模块是对功能的整理,包则是对模块的进一步整理,一个包中可以包含多个模块,也可以包含多个子包,包可以提升代码的可维护性和可复用性,便于管理大型项目。
Python 的包和模块类似,分为标准库包、自定义包和第三方包,封装标准库模块的自然就是标准库包,第三方包和自定义包同理。
2.1 定义包 定义包和定义模块规则也类似,报名符合标识符命名规范,不能和标准库包的名称冲突,且大小写敏感,一般用小写字母。
例如在项目根路径下,新建一个 trade 包,新建文件夹,名字和要建的包的包名一致,文件夹里面新建一个空的 __init__.py 文件,就成功创建了一个包。
存在子包时,包名就是父子包用 . 连接,就像 Java 那样,例如:org.springframework.boot
project
├── .venv
└── trade
└── __init__.py
在 Pycharm IDE 中,右键新建 Python Package 可以一气呵成将文件夹和 __init__.py 同时创建。
包中可以新建自己需要的模块,例如 order.py,pay.py。
project
├── .venv
└── trade
├── order .py
├── pay.py
└── __init__.py
2.2 引入包 对于包来说,有五种和引入模块相似的方式,在语法和用法规则都是相同的,唯一改变的是模块名前要加上包名。
模块 包 import 模块名 import 包名。模块名 import 模块名 as 别名 import 包名。模块名 as 别名 from 模块名 import 具体内容 1, 具体内容 2 … from 包名。模块名 import 具体内容 1, 具体内容 2 … from 模块名 import 具体内容 1 as 别名 1, 具体内容 2 as 别名 2 … from 包名。模块名 import 具体内容 1 as 别名 1, 具体内容 2 as 别名 2 … from 模块名 import * from 包名。模块名 import *
除了这五种和引入模块相似的语法,还有包特有的引入方式,新建一个 testpg.py 模块,测试这些方式。
project
├── .venv
├── testpg.py
└── trade
├── order .py
├── pay.py
└── __init__.py
2.2.1 from 包名 import 模块名 from trade import pay
from trade import order
print (pay.timeout)
pay.wechat_pay()
print (order.max_amount)
order.create_order()
2.2.2 from 包名 import 模块名 as 别名 from trade import pay as p
from trade import order as o
print (p.timeout)
p.wechat_pay()
print (o.max_amount)
o.create_order()
2.2.3 from 包名 import * 包和模块的 import * 导入逻辑是不一样的,并不是将包下每个模块的所有成员都导入,而是和包的 __init__.py 文件有关,__init__.py 中定义的内容才能被导入。
print ('trade init' )
a = 100
b = 200
from trade import *
print (a)
print (b)
print (timeout)
print (max_amount)
运行结果:导入包时打印 trade init,且只有 a b 能获取到。
如果要通过包引入模块,可以在 __init__.py 文件中直接 import 模块,import 也是一种定义。
print ('trade init' )
a = 100
b = 200
import order
import pay
from trade import *
print (a)
print (b)
print (order.max_amount)
pay.wechat_pay()
还可以通过 __all__ 以字符串指定包中的哪些可以被 from 包名 import * 的语法引入,无需 import 模块直接写模块名在列表中,例如下面程序,只有 order 模块和 a b 能被引入。
print ('trade init' )
a = 100
b = 200
__all__ = ['order' , 'a' , 'b' ]
2.2.4 import 包名 直接导入包,通过包名访问成员,导入的包必须在 __init__.py 中 import,通过 __all__ 指定在这种引入方式上不生效。
print ('trade init' )
import order
import pay
a = 100
b = 200
import trade
trade.order.create_order()
print (trade.a)
3. pip pip 是 Python 自带的第三方包管理器,在 Windows 下使用管理员权限打开 CMD,输入 pip 回车,就能看到提示,pip 实际上对应的是 Python 安装目录的\Scripts\pip.exe 文件。
通过 pip install 命令安装第三方包,例如:
全局环境下,第三方包和模块会被安装在 Python 安装目录的\Lib\site-packages,一同被安装的还有 numpy.libs,numpy-2.3.5.dist-info 两个文件夹,numpy.libs 是该包依赖的一些底层 C 实现的东西,numpy-2.3.5.dist-info 里面则是描述文件。
pip 自己也是一个第三方包,在安装 Python 环境时,一般默认安装 pip,只要选择了默认安装,就会被安装在 Lib\site-packages,Scripts\pip.exe 最终就是在运行 Lib\site-packages 中的 pip
pip install -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple numpy
⚠️如果在虚拟环境下执行,实现每个环境有不同的 pip 配置,虚拟环境目录下要提前创建好一个 pip.ini 文件,例如我的是:.venv\pip.ini
pip config set global.index-url https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
命令 释义 pip list当前环境中,已安装的所有第三方包 pip config list当前环境 pip 配置 pip uninstall ...从当前环境卸载指定的第三方包 pip config unset global.index-url恢复默认的 pypi 地址