如何避免Python中意外遮蔽标准库模块?
问题说明
我是Python新手,写了个生成数字的脚本,命名为numbers.py,依赖PyGame库。运行时触发错误:PyGame依赖的numpy在导入标准库numbers模块时,被我的本地numbers.py优先匹配,导致抛出AttributeError: module 'numbers' has no attribute 'Integral'。试过PyLint、Ruff等代码检查工具,但没检测出这个问题。
知道可以重命名文件,但要么得记住307个无点号的标准库名称,要么得等报错后再改名,想找更优方案——比如像C++那样区分<foo>和"foo"的导入方式,或者让代码检查工具能提前检测到遮蔽问题。
错误复现
phrogz:~/proj/ai$ ls numbers.py phrogz:~/proj/ai$ cat numbers.py import pygame phrogz:~/proj/ai$ python numbers.py Traceback (most recent call last): File "/home/phrogz/proj/ai/numbers.py", line 1, in <module> import pygame File "/home/phrogz/.local/lib/python3.11/site-packages/pygame/__init__.py", line 264, in <module> import pygame.surfarray File "/home/phrogz/.local/lib/python3.11/site-packages/pygame/surfarray.py", line 47, in <module> import numpy File "/home/phrogz/.local/lib/python3.11/site-packages/numpy/__init__.py", line 130, in <module> from numpy.__config__ import show as show_config File "/home/phrogz/.local/lib/python3.11/site-packages/numpy/__config__.py", line 4, in <module> from numpy.core._multiarray_umath import ( File "/home/phrogz/.local/lib/python3.11/site-packages/numpy/core/__init__.py", line 72, in <module> from . import numerictypes as nt File "/home/phrogz/.local/lib/python3.11/site-packages/numpy/core/numerictypes.py", line 595, in <module> _register_types() File "/home/phrogz/.local/lib/python3.11/site-packages/numpy/core/numerictypes.py", line 590, in _register_types numbers.Integral.register(integer) ^^^^^^^^^^^^^^^^ AttributeError: module 'numbers' has no attribute 'Integral'
实用解决方案
1. 配置代码检查工具提前检测
PyLint
在项目根目录创建.pylintrc文件,启用遮蔽标准库的检测规则:
[MASTER] enable=shadowing-standard-library
运行pylint numbers.py,会直接提示你本地文件遮蔽了标准库模块。
Ruff
在pyproject.toml中添加配置,开启PLW2901规则(检测标准库遮蔽):
[tool.ruff.lint] extend-select = ["PLW2901"]
执行ruff check numbers.py就能得到告警。
2. 调整项目结构(推荐长期方案)
别把脚本直接放在项目根目录,创建子目录(比如src)存放自己的代码,比如:
proj/ ├── src/ │ └── numbers.py └── ...
然后用模块方式运行:
python -m src.numbers
这样Python会优先查找标准库模块,不会被你的本地脚本干扰。
3. 临时应急方案
如果暂时不想改结构或文件名,可以在脚本开头先锁定标准库的numbers模块:
import sys import numbers # 先导入标准库模块 sys.modules['numbers'] = numbers # 强制缓存标准库版本 import pygame
但这只是临时 workaround,不推荐长期用。
4. 快速查询标准库名称
不用硬记所有标准库名,直接用命令查看:
python -c "import sys; print('\n'.join(sys.stdlib_module_names))"
或者安装stdlib-list工具:
pip install stdlib-list stdlib-list
命名前查一下,避免冲突。
5. 利用Python 3的绝对导入特性
Python 3默认使用绝对导入,确保你的脚本不会被当作标准库模块识别。如果是在包结构里,用from . import ...的相对导入,但根目录脚本还是尽量避开标准库名称。
内容的提问来源于stack exchange,提问作者Phrogz

