Python学习笔记

2026/9/9 Python

https://www.python.org/ (opens new window)

# 模块(Module)

# 什么是模块

Python 的模块(Module)是 Python 中组织代码的基本单位。

模块就是一个以 .py 结尾的 Python 文件,里面可以包含:

  • 变量
  • 函数
  • 可执行语句

# 为什么使用模块

  1. 代码复用 可以在多个程序中重复使用同一份代码。
  2. 命名空间隔离 不同模块中的变量、函数不会互相冲突。
  3. 结构清晰 把功能拆分成多个模块,便于维护和协作。

# 模块的分类

# 标准库模块

标准库模块:Python 自带,无需安装。

  • 内置模块(Built-in modules):编译进 Python 解释器,无 .py 文件
  • 非内置标准库模块:以 .py 文件形式随 Python 分发

所有内置模块都是标准库,但标准库不全是内置模块。

import sys
import math
import os
import json

# 方法一:sys.builtin_module_names
# 打印所有内置模块名,会输出一个元组
print(sys.builtin_module_names)

# 模块名 in sys.builtin_module_names,如果一个模块名在这个元组里的 = 内置模块,不在的 = 非内置(即使是标准库)。
print('math' in sys.builtin_module_names)
print('os' in sys.builtin_module_names)
print('json' in sys.builtin_module_names)

# 方法二:看 __file__ 属性
# 没有 __file__ 属性 → 内置模块(代码编译在解释器里,没有独立文件)
# 有 __file__ → 非内置(有对应的 .py 文件)
try:
    print(math.__file__)  # AttributeError 或 None → 内置模块
except AttributeError:
    pass
print(os.__file__)     # /usr/lib/python3.12/os.py → 非内置
print(json.__file__)   # /usr/lib/python3.12/json/__init__.py → 非内置

# 方法三:使用hasattr函数
print(hasattr(math, '__file__')) # # hasattr(模块, '__file__') → False 就是内置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 自定义模块

自定义模块:用户自己编写的Python 文件。

# 第三方模块

第三方模块:需要安装,例如:pip install requests

# 如何导入模块

以导入自定义模块fibonacci.py为例。fibonacci.py内容如下:

# Fibonacci numbers module

def print_fib(n):
    """Write Fibonacci series up to n."""
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def get_fib(n):
    """Return Fibonacci series up to n."""
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

# 控制 `from 模块名 import *` 的行为(限制可以导入哪些内容)
__all__ = ['print_fib', 'get_fib']

if __name__ == '__main__':
    # 直接运行 `fibonacci.py` 会执行以下测试代码,被导入时不会自动执行
    print_fib(5)
    result = get_fib(5)
    print(result)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  1. 基本导入:import 模块名
import fibonacci

fibonacci.print_fib(5)
1
2
3
  1. 给模块起别名:import 模块名 as 别名
import fibonacci as fibo

fibo.print_fib(5)
1
2
3
  1. 导入指定内容:from 模块名 import 具体内容1, 具体内容2, ...
from fibonacci import print_fib

print_fib(5)
1
2
3
  1. 给指定内容起别名:from 模块名 import 具体内容1 as 别名1, 具体内容2 as 别名2, ...
from fibonacci import print_fib as pf

pf(5)
1
2
3
  1. 导入所有内容(不推荐,容易造成命名冲突,一般不建议使用。):from 模块名 import *
from fibonacci import *

print_fib(5)
1
2
3

# 模块属性:__all__ —— 控制"导出什么"

问题场景

假设你写了这个包:

# mypkg/utils.py

def helper():
    pass

def _internal_helper():   # 内部函数,不希望被外部用
    pass
1
2
3
4
5
6
7

用户执行:

from mypkg.utils import *
1

结果 _internal_helper 也被导入了!这不是你想要的。

解决方案:__all__

# mypkg/utils.py

__all__ = ["helper"]   # 只有 helper 会被 * 导入

def helper():
    pass

def _internal_helper():   # 内部函数,不希望被外部用
    pass
1
2
3
4
5
6
7
8
9

现在:

from mypkg.utils import *
helper()              # ✅ 正常
_internal_helper()    # ❌ NameError
1
2
3

重要细节

情况 from xxx import * 的行为
定义了 __all__ 只导入 __all__ 里列出的名字
没定义 __all__ 导入所有不以下划线 _ 开头的名字
名字以下划线开头 默认不会被 * 导入(约定俗成的"私有")

⚠️ __all__ 只影响 import *,不影响普通导入:

from mypkg.utils import _internal_helper  # ✅ 仍然可以
1

一句话总结:__all__ = 白名单,控制 import * 时导出哪些名字

# 模块属性:__name__ —— 控制"我是谁、我怎么被用的"

每个模块都有一个内置变量 __name__

  • 如果模块是被直接运行的:__name__ == "__main__"
  • 如果模块是被导入的:__name__ == 模块名

# 模块的搜索路径

执行 import xxx 时,解释器按顺序来:

  1. 内置模块(在 sys.builtin_module_names 里,如 sysmath)→ 命中就用,不走路径
  2. sys.path[0]:空字符串 '' 表示「当前执行脚本所在目录」;交互式/-c 下是当前工作目录
  3. PYTHONPATH 环境变量里列出的目录(如果有)
  4. 标准库目录(Python 安装目录下的 lib/pythonX.Y/
  5. site-packages(含全局、用户级、虚拟环境级)——第三方包所在地
  6. .pth 文件里注册的额外路径(site 模块启动时读取)

一旦在某一步找到同名模块/包,立刻停止,后面不再看。所以「当前目录 > PYTHONPATH > site-packages」。

# 包(Package)

# 什么是包

包是包含多个模块的文件夹,必须包含 __init__.py 文件( __init__.py 文件可以为空)。

目录结构示例:

my_package/
├── __init__.py
├── module_a.py
└── module_b.py
1
2
3
4

# 如何导入包

导入方式:

  1. 基本导入:

import 包名:不等于自动能访问子模块

import 包名.模块名

  1. 起别名导入:

import 包名 as 别名

import 包名.模块名 as 别名

  1. 导入指定内容:

    from 包名 import 模块名1, 模块名2, ...

    from 包名.模块名 import 具体内容1, 具体内容2, ...

  2. 给指定内容起别名:

    from 包名 import 模块名1 as 别名1, 模块名2 as 别名2, ...

    from 包名.模块名 import 具体内容1 as 别名1, 具体内容2 as 别名2, ...

  3. 导入所有内容(不推荐,容易造成命名冲突,一般不建议使用。):

    from 包名 import *:受 包/__init__.py__all__ 影响

    from 包名.模块名 import *:受 模块 __all__ 影响;无则导入非下划线开头名字

# 包初始化文件:__init__.py

为什么需要它?

Python 3.3 之前,没有 __init__.py 的文件夹不被视为包,你没法用 import 导入里面的模块。

Python 3.3+ 引入了"命名空间包",技术上可以没有它了。但实际项目中几乎都会保留,因为它有三个核心作用:

作用 1:包的初始化代码

当包被导入时,__init__.py 里的代码会自动执行一次

这适合放:

  • 包的版本号
  • 全局配置
  • 需要在导入时自动执行的初始化逻辑

作用 2:控制 from 报名 import * 的行为

__init__.py 里定义 __all__

作用 3:简化导入路径(最常用)

假设你的包结构是这样的:

mypkg/
├── __init__.py
├── utils.py        # 里面有函数 helper()
├── models.py       # 里面有类 User()
└── views.py        # 里面有函数 render()
1
2
3
4
5

没有 __init__.py 帮忙时,用户得这么导入:

from mypkg.utils import helper
from mypkg.models import User
from mypkg.views import render
1
2
3

__init__.py 里做"重新导出":

# mypkg/__init__.py

from .utils import helper
from .models import User
from .views import render
1
2
3
4
5

用户就可以这样用:

from mypkg import helper, User, render
1

甚至:

import mypkg
mypkg.helper()
1
2

这就是很多流行库(如 requestsflask)让你能用极短路径导入的原因。

作用 4:作为包的"门面"(Facade 模式)

你可以在 __init__.py 里只暴露对外 API,隐藏内部实现细节:

# mypkg/__init__.py

from .public_api import do_something, do_another_thing

__version__ = "2.0.0"
1
2
3
4
5

用户完全不需要知道 public_api.py 的存在,只管:

import mypkg
mypkg.do_something()
1
2

内部结构怎么改都不影响用户代码。

一句话总结:__init__.py = 包的"入口文件",负责初始化 + 简化导入 + 隐藏实现

# 判断电脑是否安装 Python & 定位 Python 环境

# 1. 快速判断:有没有装 Python?

在终端 / 命令行执行:

python --version
python3 --version	# macOS/Linux 专用
py --version		# Windows 专用
1
2
3

看到类似 Python 3.11.6已安装,且当前在 PATH 中可找到。

看到 command not found / 'python' is not recognized...不一定没装,可能是只装了 python3py,或没加入 PATH

若已安装,可进一步列出所有已注册版本:

py --list
1

也可进入交互解释器验证:

python
1

看到 >>> 提示符即表示可用,输入 exit() 退出。

# 2. 看装在哪里:which / where

当我们输入:

which python    # Linux / macOS
where python    # Windows
1
2

系统会按 PATH 环境变量的顺序查找,告诉你当前实际调用的 python 在哪里。

看到的会是具体路径,例如:

  • /usr/bin/python
  • /usr/local/bin/python
  • C:\Python311\python.exe
  • /home/user/venv/bin/python

👉 也就是说,直接敲 python 时,用的就是这里显示的第一个。即当前 python 主解释器。

如果激活了虚拟环境,通常会看到 venv 里的那个路径,因为它被临时放到了 PATH 最前面。

# 3. 终极确认:当前真正使用的是哪个解释器

直接敲 python 用的就是 which/where 显示的第一个;激活虚拟环境后会临时变成 venv 里的那个。

使用以下命令可以最终确认。输出的是当前 python 命令实际指向的解释器绝对路径,最准确。

python -c "import sys; print(sys.executable)"
1

也可顺手看版本与路径:

python -c "import sys; print(sys.version); print(sys.executable)"
1

# 4. 同一台电脑安装 多个 Python 版本

Python 版本之间“物理隔离”,靠路径区分,而不是靠覆盖。

  • 每个 Python 版本安装在不同的目录
  • 每个 Python 自带:
    • 自己的解释器
    • 自己的 pip
    • 自己的 site-packages(第三方库)
  • 操作系统通过 PATH 顺序启动器 决定“用哪一个”

# 5. py.exe

py.exe 是 Windows 上 Python 官方提供的“Python 启动器(Python Launcher)”。

  • 位置:C:\Windows\py.exe
  • 作用:在 Windows 上统一管理多个已安装的 Python 版本
  • 本质:一个小型可执行程序,不负责运行代码,只负责**“帮你选一个 Python 去运行”**

✅ 1. 列出所有已安装的 Python

py --list
1

👉 这是判断“Windows 上到底装了哪些 Python”的最权威方式

✅ 2. 指定版本运行 Python

py -3.12 main.py
py -3.11 main.py
1
2

👉 完全不依赖 PATH

✅ 3. 运行模块(等价于 python -m)

py -3.12 -m pip install requests
py -3.11 -m venv .venv
1
2

👉 这是 Windows 上最稳的写法

✅ 4. 作为 .py 文件的默认打开方式

hello.py → py.exe hello.py
1

👉 Windows 默认把 .py 文件关联到 py.exe, 而 py.exe 会根据文件里的 shebang 自动选版本。

脚本里的 shebang:

#!python3.11
1

例如:

#!python3.13
import sys

print(sys.version)
print(sys.executable)
1
2
3
4
5
对比项 py python
来源 Python 官方启动器 某个 Python 安装目录里的解释器
是否依赖 PATH ❌ 不依赖 ✅ 依赖
是否支持多版本 ✅ 原生支持 ❌ 只能用一个
是否推荐 ✅ Windows 首选 ⚠️ 有 PATH 风险
是否稳定 ✅ 非常稳定 ⚠️ 可能指向错版本

Windows 上,优先用 py

# python -m

# python -m 是啥?

👉 用“我指定的这个 python”,去跑一个模块。

python -m 模块名
1

大白话解释:

用这个 python

→ 找到模块

→ 执行它的 __main__.py

python -m 模块名 中,前面的 python

  • 不写路径 → PATH 里第一个 python

  • 写路径 → 你指定的 python

# 为什么要用它?

核心目的只有一个:

防止用错 python / pip

# 经典用法 1:创建虚拟环境

python -m venv .venv
1

大白话解释:

  • 当前这个 python
  • 复制一份它自己
  • 建一个独立的 .venv
  • 以后包装在这个小房间里,不影响系统

激活:

# Windows
.venv\Scripts\activate

# macOS / Linux
source .venv/bin/activate
1
2
3
4
5

激活虚拟环境,本质就是改 PATH,把 venv 的 python 插到最前面

# 经典用法 2:装包(最重要)

python -m pip install requests
1

大白话解释:

用我前面这个 python

→ 运行它自带的 pip

→ 把包装进它自己的 site-packages

✅ 保证:

  • pythonpip 是一对
  • import requests 一定能找到

为什么不直接用 pip

写法 大白话
pip install xxx 用 PATH 里第一个 pip,不知道它跟谁是一对
python -m pip install xxx 明确用这个 python 的 pip

👉 pip 只是 python 的一个模块,python 才是老大。

# PyPI(Python Package Index,Python 包索引)官网

https://pypi.org/ (opens new window) 就是 PyPI(Python Package Index,Python 包索引) 的官方网站,由 Python 软件基金会(PSF)维护,是 Python 生态的默认公共包仓库

  • 对开发者(使用者):它是"应用商店"。你运行 python -m pip install requests,pip 默认就是从 pypi.org 下载包及其依赖,再装进对应环境的 site-packages
  • 对作者(发布者):它是"发布平台"。开发者用 twine / hatch / flit 把打好的包(wheel 或 sdist)传上去,全世界的 Python 用户都能 pip install 到。

# pip(Package Installer for Python)

pip, Package Installer for Python,Python包管理器。

# pip --version

查看 pip 版本。用于确认 pip 是否存在、版本号,以及它绑定到哪个 Python 解释器/路径。

pip --version
1

# pip config

查看当前 pip 配置。可以看到是否已经配置了 global.index-url 等。

pip config list
1

配置镜像源。修改当前用户/环境层面的 pip 配置,之后执行 pip install 包名 会默认走这个镜像。

pip config set global.index-url 地址
1

常用国内镜像,都是同步 pypi.org 的,配置时地址一般要指向 /simple 结尾的索引地址。

  • 清华大学 TUNA:https://pypi.tuna.tsinghua.edu.cn/simple
  • 阿里云:https://mirrors.aliyun.com/pypi/simple/
  • 中国科学技术大学:https://pypi.mirrors.ustc.edu.cn/simple/
  • 腾讯云:https://mirrors.cloud.tencent.com/pypi/simple/
  • 华为云:https://repo.huaweicloud.com/repository/pypi/simple/

恢复官方默认地址。恢复后,pip install 默认从官方 PyPI (https://pypi.org/) 获取。

pip config unset global.index-url
1

# pip install

pip install 会把包装进当前 pip 绑定的那个 Python 解释器对应的 site-packages。常见位置:

  • 系统全局(全局环境/系统环境)Linux /usr/local/lib/python3.X/site-packagesWindows C:\Python3X\Lib\site-packages
  • 用户级pip install --user):Linux ~/.local/lib/python3.X/site-packagesWindows %APPDATA%\Python\Python3X\site-packages
  • 虚拟环境项目/.venv/lib/python3.X/site-packages

安装最新版。默认从 PyPI(或你配置的镜像源)安装第三方包的最新稳定版本。

pip install 包名
1

安装指定版本。如果已经安装了其他版本,pip 通常会先卸载当前版本,再安装指定版本。版本号必须是 PyPI/镜像源中存在的版本。

pip install 库名==版本号
1

也支持版本范围。注意:在 bash/zsh 等终端里,含 >, <, = 的表达式建议加引号,避免被 shell 误解析。

pip install "numpy>=1.21.0"
pip install "flask<3.0"
pip install "requests>=2.20.0,<3.0"
1
2
3

临时使用镜像安装。只对本次安装生效,不会修改全局配置。

pip install -i 镜像地址 包名
1

升级包

  • 如果库已安装:升级到索引源上的最新版本。
  • 如果库未安装:相当于 pip install 库名,直接安装最新版。
pip install --upgrade 库名
pip install -U 库名
1
2

按依赖文件安装。读取文件中的包名和版本约束,批量安装依赖。

pip install -r requirements.txt
pip install -r ./requirements.txt # 指定路径
1
2

requirements.txt 用来记录当前 Python 环境里需要的第三方包及版本,方便别人或自己在另一个环境里一键安装,保证依赖一致。常用于项目环境复现、部署、协作。

每行一个依赖,示例:

requests==2.28.1
numpy>=1.21.0
flask==2.2.5
# 工具包
pytest>=7.0.0
1
2
3
4
5

说明:

  • ==:固定版本
  • >=:最低版本
  • 也可以写 <, <=, ~= 等版本约束
  • # 后面可写注释

# pip freeze

导出当前环境依赖。会把当前环境已安装包和精确版本写入文件。

pip freeze > requirements.txt
pip freeze > ./requirements.txt
1
2

注意:pip freeze 通常会导出当前环境中很多包,包括间接依赖。若想让依赖文件更干净,可以手动维护只写项目直接依赖;或者配合虚拟环境使用,避免混入全局包。

# pip uninstall

卸载包。从当前 Python 环境中卸载指定的第三方包。

pip uninstall 包名
1

# pip list

查看已安装包。列出当前环境已安装的所有第三方包及版本。

pip list
1

# pip show

看某个包信息

pip show 包名
1