Skip to content

启动文件与配置 ​

Python 的交互式解释器在启动时会做一系列初始化:设置 sys.path、加载 site 模块、读取环境变量、执行 PYTHONSTARTUP 指定的脚本。理解这套启动顺序,就能把提示符、补全、历史、常用导入等个性化配置放在正确的位置。

前置知识

阅读本节前,建议先了解:颜色高亮与自动补全

基础概念 ​

Python 启动时涉及多个「配置文件」与「环境变量」,职责各不相同:

名称是否只影响交互模式作用
PYTHONSTARTUP是指向启动脚本,交互模式启动时执行
sitecustomize.py否site 模块自动导入,影响所有 Python 进程
usercustomize.py否类似 sitecustomize,面向用户级自定义
site.py / .pth 文件否路径扩展与 site 初始化
PYTHONPATH否追加模块搜索路径
PYTHONHISTORY是自定义历史文件位置
PYTHONCOERCECLOCALE 等否解释器行为微调

关键区别在于作用范围:

  • PYTHONSTARTUP 只在交互模式下执行,脚本运行时不执行。因此可以放心放交互专用的便利设置。
  • sitecustomize.py / usercustomize.py 影响所有 Python 进程,包括你运行的每个脚本和工具,改动需谨慎。
  • .pth 文件在 site 初始化时逐行处理,常用于把额外目录加入 sys.path。

Python 的启动顺序(简化):

text
1. 解释器初始化,处理命令行参数(-c、-m、-i、-E、-S 等)
2. 初始化 sys.path(含脚本目录、PYTHONPATH、标准库、site-packages)
3. 若未指定 -S,导入 site 模块
   ├─ 处理 site-packages 下的 .pth 文件
   ├─ 尝试导入 sitecustomize
   └─ 尝试导入 usercustomize
4. 若处于交互模式且设置了 PYTHONSTARTUP,执行该脚本
5. 进入 REPL 循环或执行脚本

因此,PYTHONSTARTUP 是最后执行的,它的设置会覆盖前面阶段的默认值。

语法与用法 ​

设置 PYTHONSTARTUP:

bash
# Bash / Zsh:写入 ~/.bashrc 或 ~/.zshrc
export PYTHONSTARTUP="$HOME/.pythonrc.py"

# Fish
set -Ux PYTHONSTARTUP "$HOME/.pythonrc.py"

# 验证环境变量已生效
echo "$PYTHONSTARTUP"

创建一个最小的启动脚本:

python
# ~/.pythonrc.py
"""Python 交互式解释器的启动脚本。"""
import sys

print(f"Python {sys.version.split()[0]} 交互会话已就绪")

启动验证:

bash
python
# 输出:Python 3.13.1 交互会话已就绪
# 随后进入 >>> 提示符

确认启动脚本确实只在交互模式执行:

bash
# 交互模式:会打印提示
python
# Python 3.13.1 交互会话已就绪

# 脚本模式:不会打印
echo 'print("脚本运行")' > demo.py
python demo.py
# 脚本运行

sitecustomize.py 的用法不同,它需要放在 sys.path 能找到的位置(通常在 site-packages):

python
# sitecustomize.py(放在 site-packages 目录)
import sys

# 该文件会在所有 Python 进程启动时被导入
if sys.version_info < (3, 10):
    raise RuntimeError("本环境要求 Python 3.10 及以上")

用 .pth 文件扩展路径:

text
# mypaths.pth(放在 site-packages 目录,每行一个路径)
/Users/demo/work/libs
/Users/demo/work/tools

验证 .pth 是否生效:

bash
python -c "import sys; print([p for p in sys.path if 'libs' in p])"
# ['/Users/demo/work/libs']

详细说明 ​

PYTHONSTARTUP 的执行时机与限制 ​

该变量指向的脚本仅在交互模式下执行,具体条件:

  • 解释器启动后进入交互模式(无脚本参数,或使用 -i);
  • 环境变量 PYTHONSTARTUP 指向一个存在的文件;
  • 未设置 -E(-E 会忽略所有 PYTHON* 环境变量)。

若脚本本身抛异常,解释器会打印回溯但继续进入 REPL,不会退出。这一点很友好——配置写错不会导致无法启动。

python
# 故意写错以观察行为
undefined_name  # 启动时会打印 NameError,但仍能进入 REPL
bash
$ python
Traceback (most recent call last):
  File "/Users/demo/.pythonrc.py", line 2, in <module>
    undefined_name
NameError: name 'undefined_name' is not defined
>>>

启动脚本中可用的上下文 ​

PYTHONSTARTUP 脚本在一个特殊命名空间中执行:它不是 __main__,但其中的全局变量会成为交互会话的初始命名空间。因此:

python
# ~/.pythonrc.py
# 这些名字在进入 REPL 后可直接使用
import datetime
import json
from pathlib import Path

today = datetime.date.today
home = Path.home()
python
>>> today()
datetime.date(2026, 10, 8)
>>> home
PosixPath('/Users/demo')
>>> json.dumps({"ok": True})
'{"ok": true}'

这使启动脚本成为「预导入常用模块」的理想位置。但要注意:不要在这里导入过重的库(如 pandas、torch),否则每次启动 REPL 都会变慢。

__file__ 在该脚本中指向 PYTHONSTARTUP 的路径,可用于定位同目录的辅助文件。

自定义提示符 ​

sys.ps1 与 sys.ps2 只在交互模式下存在,可在启动脚本中修改:

python
# ~/.pythonrc.py
import sys

# 显示当前路径与 Python 版本
sys.ps1 = "py> "
sys.ps2 = "..> "

用颜色装饰提示符(需要终端支持 ANSI):

python
# ~/.pythonrc.py
import sys

GREEN = "\001\033[32m\002"
RESET = "\001\033[0m\002"

# 注意:\001 与 \002 是 readline 的「不可见字符」标记,
# 避免计算光标位置时把转义序列算进宽度
sys.ps1 = f"{GREEN}>>> {RESET}"
sys.ps2 = f"{GREEN}... {RESET}"

若用 3.13 的新 REPL,提示符着色已内置,通常无需手动添加转义序列。

sitecustomize 与 usercustomize 的分工 ​

文件位置典型用途
sitecustomize.pysite-packages,由管理员或环境提供全环境策略,如版本校验、编码设置
usercustomize.py用户级 site-packages(如 ~/.local/lib)个人偏好,跨环境生效

usercustomize 只在未设置 -s(禁用用户站点目录)时导入。二者的差异在于作用范围与权限:前者是环境级,后者是用户级。

一个实用的 sitecustomize 示例——为所有进程统一 UTF-8 与警告策略:

python
# sitecustomize.py
import sys
import warnings

# 让所有进程默认以 UTF-8 读取源码与标准流
if hasattr(sys, "set_int_max_str_digits"):
    # 提高大整数转字符串的上限(按需设置,注意安全影响)
    sys.set_int_max_str_digits(100000)

# 统一警告过滤策略
warnings.filterwarnings("default", category=DeprecationWarning)

需要强调:sitecustomize 会影响所有 Python 进程,包括 pip、构建工具等。改动前应确认不会破坏工具链。

常用的启动脚本模板 ​

一份实用的启动脚本通常包含四块内容:

  1. 预导入常用模块;
  2. 补全与历史配置;
  3. 提示符与输出美化;
  4. 便利函数与快捷键。

下面给出一个可直接使用的完整模板。

python
# ~/.pythonrc.py
"""Python 交互式解释器的启动配置(完整模板)。"""
from __future__ import annotations

import atexit
import os
import readline
import rlcompleter
import sys
from pathlib import Path

# ---------- 1. 预导入常用模块 ----------
import datetime
import itertools
import json
import math
import random
import re

# ---------- 2. 补全 ----------
_completer = rlcompleter.Completer()


def _path_aware(text: str, state: int) -> str | None:
    """含路径分隔符时补全文件名,否则交给 rlcompleter。"""
    if os.sep in text:
        directory, prefix = os.path.split(text)
        base = directory or "."
        try:
            matches = [n for n in sorted(os.listdir(base)) if n.startswith(prefix)]
        except OSError:
            return None
        if state < len(matches):
            return os.path.join(directory, matches[state]) if directory else matches[state]
        return None
    return _completer.complete(text, state)


readline.set_completer(_path_aware)
readline.parse_and_bind("tab: complete")
readline.set_completer_delims(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?")

# ---------- 3. 历史 ----------
HISTORY = Path(os.environ.get("PYTHON_HISTORY", Path.home() / ".python_history"))
if HISTORY.exists():
    readline.read_history_file(HISTORY)
readline.set_history_length(2000)
atexit.register(readline.write_history_file, HISTORY)

# ---------- 4. 便利工具 ----------
def pwd() -> str:
    """返回当前工作目录,方便在 REPL 中查看。"""
    return os.getcwd()


def reload(module: object) -> None:
    """重新导入模块,便于开发时快速验证改动。"""
    import importlib

    importlib.reload(module)


print(f"Python {sys.version.split()[0]} | Tab 补全、历史已启用 | 试试 pwd()")

保存为 ~/.pythonrc.py 并在 Shell 中导出 PYTHONSTARTUP 即可生效。

环境变量与命令行开关的交互 ​

-E 会忽略所有 PYTHON* 环境变量,因此 PYTHONSTARTUP 也会失效:

bash
# 正常:会执行启动脚本
python

# 忽略环境变量:启动脚本不执行
python -E

# 跳过 site 模块:sitecustomize/usercustomize 不导入
python -S

# 先运行脚本再进入交互(会执行启动脚本)
python -i script.py
开关影响
-E忽略 PYTHON* 环境变量(含 PYTHONSTARTUP、PYTHONPATH、PYTHONHISTORY)
-S不导入 site,sitecustomize/usercustomize/.pth 全部跳过
-s不把用户级 site-packages 加入 sys.path
-I隔离模式,等价于 -E -s 再加其他限制
-i执行脚本后进入交互模式(此时执行启动脚本)

排查配置问题时,python -E 与 python -S 是最快的定位手段:前者禁用所有环境变量,后者禁用站点初始化。

让配置在虚拟环境与容器中同样生效 ​

PYTHONSTARTUP 是用户级设置,虚拟环境不会覆盖它,因此配置在所有 venv 中都有效。但要注意:

  • 启动脚本中不要硬编码某个虚拟环境的路径;
  • 若启动了 -I 或 -E(如某些工具内部使用),配置不会生效,这是正常行为;
  • 容器中若未设置 PYTHONSTARTUP,可写进镜像的 Shell 初始化或 ENV 指令;
  • 共享服务器上应把个人配置放在用户目录,不要写进系统级 sitecustomize。

与 -i 模式的配合 ​

python -i script.py 会先执行脚本,再进入交互模式,此时启动脚本会被执行。因此用 -i 调试时也能享受补全与历史。但顺序上,启动脚本先执行,脚本后执行,脚本中的定义会覆盖启动脚本的同名变量。

bash
python -i explore.py
# 先打印启动脚本的提示,再执行 explore.py,最后进入 REPL

实战示例 ​

示例一:为数据探索准备启动环境 ​

做数据分析时,常需要反复导入若干库。把它们放进启动脚本,可省去重复输入。

python
# ~/.pythonrc_data.py
"""数据探索专用的启动脚本。"""
from __future__ import annotations

import csv
import datetime as dt
import json
import statistics
from pathlib import Path


def load_csv(path: str | Path) -> list[dict[str, str]]:
    """读取 CSV 文件,返回字典列表。"""
    with Path(path).open(encoding="utf-8", newline="") as handle:
        return list(csv.DictReader(handle))


def summarize(values: list[float]) -> dict[str, float]:
    """返回一组数值的常用统计量。"""
    return {
        "count": len(values),
        "mean": statistics.fmean(values),
        "median": statistics.median(values),
        "stdev": statistics.pstdev(values),
    }
bash
# 使用时切换启动脚本
PYTHONSTARTUP=~/.pythonrc_data.py python
python
>>> rows = load_csv("sales.csv")
>>> summarize([float(r["amount"]) for r in rows])
{'count': 120, 'mean': 218.4, 'median': 199.0, 'stdev': 87.3}

启动脚本成为「探索环境的一部分」,比每次手敲导入更可靠。

示例二:用 sitecustomize 统一团队的编码与警告策略 ​

团队希望所有脚本默认使用 UTF-8,并把废弃警告显式暴露出来。这适合放在环境级配置中。

python
# sitecustomize.py(放在项目虚拟环境的 site-packages 中)
"""环境级启动配置:统一编码与警告策略。"""
import sys
import warnings

# 确保标准输出/错误使用 UTF-8(部分 Windows 环境默认是 GBK)
if sys.stdout.encoding and sys.stdout.encoding.lower() not in {"utf-8", "utf8"}:
    try:
        sys.stdout.reconfigure(encoding="utf-8")  # type: ignore[union-attr]
        sys.stderr.reconfigure(encoding="utf-8")  # type: ignore[union-attr]
    except AttributeError:
        pass  # 老版本或非文本流,忽略

# 让废弃警告可见,推动代码保持现代写法
warnings.filterwarnings("default", category=DeprecationWarning)

把该文件放进虚拟环境的 site-packages,则该环境下的所有进程都会生效。验证:

bash
python -c "import sys; print(sys.stdout.encoding)"
# utf-8

注意:sitecustomize 只在 site 初始化时被导入,使用 -S 启动的进程不会加载它。

示例三:用 .pth 文件注入团队公共库 ​

团队有一套内部工具库放在共享目录,希望所有项目都能直接导入。用 .pth 是最轻量的方式。

text
# team_libs.pth(放在 site-packages 目录)
/opt/team/libs
/opt/team/vendor

也可以利用 .pth 的 import 语法执行一行代码:

text
# enable_team_hooks.pth
import sys; sys.path.insert(0, "/opt/team/libs")

不过这行代码只在路径不存在时才应执行,更稳妥的写法是用普通路径行(第一行形式)。验证注入是否生效:

python
>>> import sys
>>> [p for p in sys.path if "team" in p]
['/opt/team/libs', '/opt/team/vendor']

示例四:诊断启动配置是否按预期生效 ​

当配置「看起来没生效」时,用一段脚本逐项核对。

python
# check_startup.py
from __future__ import annotations

import importlib.util
import os
import sys


def check() -> list[tuple[str, str]]:
    """检查各类启动配置的生效情况。"""
    startup = os.environ.get("PYTHONSTARTUP")
    rows: list[tuple[str, str]] = [
        ("PYTHONSTARTUP", startup or "<未设置>"),
        ("启动脚本存在", str(bool(startup) and os.path.isfile(startup))),
        ("PYTHONPATH", os.environ.get("PYTHONPATH", "<未设置>")),
        ("PYTHONHISTORY", os.environ.get("PYTHONHISTORY", "<未设置>")),
        ("交互模式", str(hasattr(sys, "ps1"))),
        ("忽略环境变量(-E)", str(sys.flags.ignore_environment == 1)),
        ("跳过 site(-S)", str(sys.flags.no_site == 1)),
        ("sitecustomize 可导入", str(importlib.util.find_spec("sitecustomize") is not None)),
        ("usercustomize 可导入", str(importlib.util.find_spec("usercustomize") is not None)),
    ]
    return rows


if __name__ == "__main__":
    for name, value in check():
        print(f"{name:24} {value}")

重点看两项:交互模式 若为 False,说明当前是脚本模式,启动脚本本就不会执行;忽略环境变量(-E) 若为 True,则所有 PYTHON* 变量都被跳过。

注意事项 ​

  • PYTHONSTARTUP 只在交互模式生效:在脚本里依赖它必然失败,跨模式共享的逻辑应放 sitecustomize。
  • 不要硬编码虚拟环境路径:启动脚本是用户级的,硬编码会污染其他环境。
  • 启动脚本异常不会阻止启动:会打印回溯但继续进入 REPL,容易误以为配置生效了,需留意输出。
  • sitecustomize 影响所有进程:写错会影响 pip、构建工具等,改动前务必在隔离环境验证。
  • -E 会禁用全部 PYTHON* 变量:排查问题时先用它确认是否与环境变量有关。
  • -S 会跳过 site、.pth、usercustomize:诊断站点配置问题时用它对照。
  • 不要在启动脚本里做重活:导入大型库或执行网络请求会显著拖慢每次启动。
  • sys.ps1 只在交互模式存在:脚本中访问会抛 AttributeError,需先判断。
  • .pth 文件的一行一路径:空行与 # 开头的行会被忽略,路径中不要带引号。

常见问题 ​

Q:设置了 PYTHONSTARTUP 但没生效? 依次检查:文件路径是否正确、Shell 是否重新加载配置、是否用了 -E、当前是否交互模式。

Q:PYTHONSTARTUP 与 PYTHONPATH 有什么区别? 前者是「要执行的脚本」,后者是「模块搜索路径」。一个改变行为,一个改变导入范围。

Q:启动脚本会随虚拟环境变化吗? 不会。PYTHONSTARTUP 是用户级环境变量,所有 venv 共用。需要环境级配置请用 sitecustomize。

Q:能在启动脚本中自动激活虚拟环境吗? 不推荐。虚拟环境的激活应由 Shell 负责,在启动脚本中修改 sys.path 容易造成混乱。

Q:如何临时禁用启动脚本?PYTHONSTARTUP= python 或 python -E。

Q:usercustomize 和 sitecustomize 冲突吗? 不冲突,二者都会导入。一般约定 sitecustomize 由环境提供,usercustomize 由用户提供。

最佳实践 ​

  1. 交互专用配置放 ~/.pythonrc.py,通过 PYTHONSTARTUP 加载。
  2. 环境级、影响所有进程的配置放 sitecustomize.py,并纳入版本控制。
  3. 启动脚本只做轻量操作:预导入、补全、历史、便利函数。
  4. 用 -E 与 -S 快速定位配置问题,先排除环境变量再排查代码。
  5. 用诊断脚本定期核对配置生效情况,尤其在换机器后。
  6. 不在启动脚本中硬编码路径或做网络访问。
  7. 把启动脚本纳入 dotfiles 仓库管理,便于在多台机器间同步。

下一节

下一章将进入语言规范与社区:Python 之禅 Zen of Python

参考链接 ​