Python中的模块和包

本文最后更新于 2026年8月21日

未完待续

包和模块是Python语言封装功能和组织程序集的解决方案,类似Java中的package和C#中的namespace,将固定功能模块的代码聚合在一起,提高程序的复用性和可维护性。

模块和包在不同环境下位置和作用范围也不一样,可参考:Python全局环境和虚拟环境(venv)

1.模块

每一个.py文件都是一个模块,每个模块中可以包含变量,函数,类等内容,模块,多用于封装固定功能的代码,每个模块都是一个工具,模块可以提升代码的可维护性和可复用性,还能避免命名冲突。

python中的模块分为三种:标准库模块,自定义模块和第三方模块

  • 标准库模块

    随着Python自带的一些模块,位于Python安装目录的\Lib下(site-packages中的除外),有些是C语言实现的,不能看到源码(Pycharm IDE会为我们准备存根文件,里面仅有注释)也叫内置模块,剩下是python实现,可见源码,叫做非内置模块,例如:copy, os, math, sys, time等都是标准库模块,其中的math, sys, time就是内置模块,copy, os就是非内置模块

    有些模块是用包进行组织的,包的概念后面会有介绍

    python提供了标准库文档用于参考:https://docs.python.org/zh-cn/3.14/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 引入模块

在根目录建一个新的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()

50000000
300
create_order
cancel_order
alipay_pay
wechat_pay
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 *

max_amount = 5

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()

300
5
alipay_pay
wechat_pay
create_order
cancel_order
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代码一样

例如:

mytest.py(主模块)

import son

print('主模块执行-开始')

print(__name__)

son.fun()

son.py

print('son模块执行-开始')

def fun():
    print(__name__)

运行结果就是上面说的那样:son模块print先执行了,然后主模块print后执行,而且__name__被解释器自动赋上对应的值

son模块执行-开始
主模块执行-开始
__main__
son

这样设计的用途是,可以对某个模块内自己实现的方法进行简单测试,类似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 模块名

testpg.py

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 别名

testpg.py

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中定义的内容才能被导入

trade/__init__.py

print('trade init')

a = 100
b = 200

testpg.py

from trade import *

print(a)
print(b)

print(timeout)
print(max_amount)

运行结果:导入包时打印trade init,且只有a b能获取到

trade init
100
200
Traceback (most recent call last):
  File "D:\python-lang-test\test1\testpg.py", line 29, in <module>
    print(timeout)
          ^^^^^^^
NameError: name 'timeout' is not defined

Process finished with exit code 1

如果要通过包引入模块,可以在__init__.py文件中直接import模块,import也是一种定义

trade/__init__.py

print('trade init')

a = 100
b = 200

import order
import pay

testpg.py

from trade import *

print(a)
print(b)

print(order.max_amount)
pay.wechat_pay()

还可以通过__all__以字符串指定包中的哪些可以被from 包名 import *的语法引入,无需import模块直接写模块名在列表中,例如下面程序,只有order模块和a b能被引入

trade/__init__.py

print('trade init')

a = 100
b = 200

__all__ = ['order', 'a', 'b']

2.2.4 import 包名

直接导入包,通过包名访问成员,导入的包必须在__init__.py中import,通过__all__指定在这种引入方式上不生效

trade/__init__.py

print('trade init')

import order
import pay

a = 100
b = 200

testpg.py

import trade

trade.order.create_order()
print(trade.a)

3.pip

pip是python自带的第三方包管理器,在windows下使用管理员权限打开CMD,输入pip回车,就能看到提示,pip实际上对应的是python安装目录的\Scripts\pip.exe文件

第三方包要到pypi的网站查找:https://pypi.org/,就像从maven中央仓库和npm查找Java或js的第三方依赖那样。

通过pip install命令安装第三方包,例如:

pip install numpy

全局环境下,第三方包和模块会被安装在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

pypi的服务器在境外,夜间可能访问不稳定,因此可以使用国内的一些镜像,例如清华大学pypi镜像:https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple

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还有以下几个常见用法:

命令 释义
pip install 包==版本号 当前环境中,安装某个版本的某包
pip install -r requirements.txt 从requirements.txt安装包到当前环境
pip list 当前环境中,已安装的所有第三方包
pip config list 当前环境pip配置
pip uninstall ... 从当前环境卸载指定的第三方包
pip config unset global.index-url 恢复默认的pypi地址
pip install git+https://github.com/** 从Git仓库地址安装包
pip install "langchain[anthropic]" extras语法,方括号[]用来安装可选的功能扩展
pip freeze 当前环境已安装的包,可写入requirements.txt
pip uninstall 包 卸载包,不支持级联卸载间接依赖包

pip还支持从官方标准指定的pyproject.toml项目配置文件安装包,pyproject.toml可以指定项目名称,版本,python版本(requires-python = ""),各种依赖模块和包的版本(dependencies = []),供各种项目管理工具读取使用,这个文件可共享到git

先新建一个pyproject.toml文件在根目录,再声明所需依赖

pyproject.toml

[project]
name = "my-project"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
authors = [
    { name = "liuzijian", email = "me@liuzijian.com" }
]
requires-python = ">=3.12"
dependencies = [
    "loguru>=0.7.3"
]

然后执行pip install .命令,就会安装pyproject.toml中声明的依赖了

但是在开发阶段,建议使用pip install -e .进行安装,因为pip install .命令会将我们自己写的模块也安装进环境,每次代码改动不会自动同步,-e参数只将我们自己的模块创建链接,不拷贝文件

4.uv

uv是一款基于Rust语言编写的高性能的python包和环境管理工具,不但能代替pip下载依赖,还可以统一管理项目的依赖版本,python版本和venv,底层仍是操作pip/venv

比起传统pip,uv的优点是:

  1. 安装依赖很快,多线程下载
  2. 不但能管理依赖版本和下载依赖,还能管理python版本和下载python
  3. 本地缓存机制,新项目不需再次下载相同的包
  4. 根据配置,对新clone的项目一键生成项目环境:创建venv/安装依赖/激活python版本
  5. 能支持管理间接依赖

下载地址:https://github.com/astral-sh/uv/releases,解压将可执行文件目录放进环境变量即可

首先可以uv python list命令,查看当前uv识别到已存在的python版本,有些是其他途径下载安装进去的也能被识别到

D:\PycharmProjects>uv python list
cpython-3.15.0rc1-windows-x86_64-none                 <download available>
cpython-3.15.0rc1+freethreaded-windows-x86_64-none    <download available>
cpython-3.14.7-windows-x86_64-none                    <download available>
cpython-3.14.7+freethreaded-windows-x86_64-none       <download available>
cpython-3.14.6-windows-x86_64-none                    D:\miniconda3\python.exe
cpython-3.13.15-windows-x86_64-none                   <download available>
cpython-3.13.15+freethreaded-windows-x86_64-none      <download available>
cpython-3.13.11-windows-x86_64-none                   D:\Python\Python313\python.exe
cpython-3.12.14-windows-x86_64-none                   <download available>
cpython-3.11.16-windows-x86_64-none                   C:\Users\lzj20\AppData\Roaming\uv\python\cpython-3.11.16-windows-x86_64-none\python.exe
cpython-3.11.16-windows-x86_64-none                   C:\Users\lzj20\AppData\Roaming\uv\python\cpython-3.11-windows-x86_64-none\python.exe
cpython-3.10.21-windows-x86_64-none                   <download available>
cpython-3.9.25-windows-x86_64-none                    <download available>
cpython-3.8.20-windows-x86_64-none                    <download available>
pypy-3.11.15-windows-x86_64-none                      <download available>
pypy-3.10.16-windows-x86_64-none                      <download available>
pypy-3.9.19-windows-x86_64-none                       <download available>
pypy-3.8.16-windows-x86_64-none                       <download available>
graalpy-3.12.0-windows-x86_64-none                    <download available>
graalpy-3.11.0-windows-x86_64-none                    <download available>
graalpy-3.10.0-windows-x86_64-none                    <download available>

没有需要的版本,可以直接uv python install <版本号>命令下载python,例如uv python install 3.11

使用uv管理python和依赖时,需访问境外源,可能不稳定,windows系统可在{home}\AppData\Roaming\uv\路径新增配置uv.toml文件,并设置以下cnb/清华大学镜像源

# 用于加速 uv python install 下载解释器
python-install-mirror = "https://cnb.cool/astral-sh/python-build-standalone/-/releases/download"

# 用于加速 uv add / uv pip install 下载第三方包
[[index]]
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
default = true

接下来,可以直接用uv创建一个my-project项目

uv init --python 3.12 my-project

会生成如下结构:

./my-project
    ├── .git
    ├── .gitignore
    ├── .python-version
    ├── pyproject.toml
    ├── README.md
    └── src/
         └── my-project
              └── __init__.py

其中:.python-version里面写了个版本号,用于锁死项目python版本,pyproject.toml则是项目配置文件

设置好python版本和依赖包后,执行uv sync命令,会根据pyproject.toml配置一键生成项目环境:生成venv/安装依赖/激活python版本,依赖或python版本不存在的uv会自动下载

D:\PycharmProjects\my-project>uv sync
Using CPython 3.12.14
Creating virtual environment at: .venv

执行后,项目根目录下会生成虚拟环境目录.venv和用于统一下载地址的uv.lock文件

接下来安装一个loguru依赖,无需激活虚拟环境,直接在根目录执行uv add loguru添加一个loguru模块到项目中,uv会自动识别并添加依赖到虚拟环境,完成后会发现,依赖已经自动加入到pyproject.toml配置文件,uv.lock文件里面保存了loguru的下载地址

使用了uv add,就尽量避免使用pip install
uv add xxx==version,可指定版本

... ...

dependencies = [
    "loguru>=0.7.3",
]

... ...

可以使用uv tree命令,查看当前项目依赖树

D:\PycharmProjects\my-project>uv tree
Resolved 3 packages in 22ms
my-project v0.1.0
└── loguru v0.7.3
    ├── colorama v0.4.6
    └── win32-setctime v1.2.0

如要修改依赖或python版本,也很简单,先修改配置pyproject.toml,然后再次执行uv sync命令,如有python版本的改动,.python-version文件中的python版本要和pyproject.toml同步修改。

如卸载依赖,可以采用uv remove loguru,或者从pyproject.toml删除依赖包再uv sync,uv移除依赖支持级联移除,不会残留孤儿依赖


当使用PyCharm打开uv创建的项目时,2026版的PyCharm能识别出并建议设置为uv项目,如不能自动识别,手动换为uv即可,uv环境按实际情况设置,解释器选择当前项目venv即可


"如果文章对您有帮助,可以请作者喝杯咖啡吗?"

微信二维码

微信支付

支付宝二维码

支付宝


Python中的模块和包
https://blog.liuzijian.com/post/python/2025/12/18/python-module-package/
作者
Liu Zijian
发布于
2025年12月18日
更新于
2026年8月21日
许可协议