自动将文件中的 'import *' 导入替换为显式导入的工具
项目描述
removestar
工具,用于自动将Python文件中的 import *
导入替换为显式导入
安装
全局安装 removestar
以通过CLI使用 pypi
-
pip install removestar
pip install "removestar[nb]" # notebook support
或者 conda
-
conda install -c conda-forge removestar
或者在 .pre-commit-config.yaml
中添加 removestar
-
- repo: https://github.com/asmeurer/removestar
rev: "1.5"
hooks:
- id: removestar
args: [-i] # See docs for all args (-i edits file in-place)
additional_dependencies: # The libraries or packages your code imports
- ... # Add . if running inside a library (to install the library itself in the environment)
- ... # Add nbformat and nbconvert for notebook support
用法
pre-commit 插件
一旦在 .pre-commit-config.yaml
中添加了 removestar
,执行以下操作将始终在每次提交前运行它(以及其他 pre-commits)-
pre-commit install
可选地,可以使用 - 手动触发所有文件的 pre-commits(包括 removestar
)
pre-commit run --all-files
命令行界面(CLI)
# scripts
$ removestar file.py # Shows diff but does not edit file.py
$ removestar -i file.py # Edits file.py in-place
$ removestar -i module/ # Modifies every Python file in module/ recursively
# notebooks (make sure nbformat and nbconvert are installed)
$ removestar file.ipynb # Shows diff but does not edit file.ipynb
$ removestar -i file.ipynb # Edits file.ipynb in-place
为什么 import *
那么糟糕?
from module import *
在 Python 中通常是不受欢迎的。在交互式使用 python
提示符或在 __init__.py
文件中工作时被认为是可接受的(removestar 默认跳过 __init__.py
文件)。
import *
糟糕的几个原因
- 它隐藏了实际导入的名称。
- 当使用
import *
时,对于人类阅读者以及像 pyflakes 这样的静态分析器来说,很难确定给定名称的来源。例如,pyflakes 无法检测到import *
存在时未使用的名称(例如,来自拼写错误)。 - 如果有多个
import *
语句,可能不清楚哪些名称来自哪个模块。在某些情况下,两个模块可能都有相同的名称,但只有第二个导入最终会被使用。这可能会打破人们对 Python 文件中导入顺序通常不重要的直觉。 import *
经常导入比预期的更多名称。除非你导入的模块定义了__all__
或在模块级别仔细del
未使用的名称,否则import *
将导入模块文件中定义的每个公共(不以下划线开头)名称。这通常包括标准库导入或文件顶级定义的循环变量。从模块(从__init__.py
)的导入中,from module import *
将包括在该模块中定义的每个子模块。在模块和__init__.py
文件中使用__all__
也是良好的实践,因为这些内容对于交互式使用import *
时也常常令人困惑。- 在 Python 3 中,
import *
在函数内部是不允许的。
以下是一些官方 Python 引用,说明不要在文件中使用 import *
-
一般来说,不要使用
from modulename import *
。这样做会使导入者的命名空间变得混乱,并使代码检查器检测未定义的名称变得更加困难。 -
PEP 8(官方 Python 风格指南)
避免使用通配符导入(
from <module> import *
),因为它们使命名空间中存在的名称变得不清楚,既使读者困惑,也使许多自动化工具困惑。
不幸的是,如果你遇到使用 import *
的文件,修复它可能很困难,因为你需要找到文件中从 *
导入的每个名称。Removestar 通过自动替换文件中的导入行来简化这个过程。
一个例外是,在代码开发的早期阶段,可能难以确定一个明确的必需函数集。在这种情况下,通配符导入可以通过避免不断维护必需函数集而有益。例如,在开发阶段使用 from os.path import *
可以节省维护必需函数的时间。在开发完成后,可以使用 removestar
确定通配符导入。话虽如此,由于多个上述原因,应该避免使用通配符导入。
示例
假设你有一个名为 mymod
的模块
mymod/
| __init__.py
| a.py
| b.py
有
# mymod/a.py
from .b import *
def func(x):
return x + y
# mymod/b.py
x = 1
y = 2
那么 removestar
将像这样工作
$ removestar mymod/
--- original/mymod/a.py
+++ fixed/mymod/a.py
@@ -1,5 +1,5 @@
# mymod/a.py
-from .b import *
+from .b import y
def func(x):
return x + y
默认情况下,此工具不会编辑 a.py
。使用 -i
标志会在原地编辑 a.py
。
$ removestar -i mymod/
$ cat mymod/a.py
# mymod/a.py
from .b import y
def func(x):
return x + y
命令行选项
$ removestar --help
usage: removestar [-h] [-i] [--version] [--no-skip-init]
[--no-dynamic-importing] [-v] [-q]
[--max-line-length MAX_LINE_LENGTH]
PATH [PATH ...]
Tool to automatically replace "import *" imports with explicit imports
Requires pyflakes.
Usage:
$ removestar file.py # Shows diff but does not edit file.py
$ removestar -i file.py # Edits file.py in-place
$ removestar -i module/ # Modifies every Python file in module/ recursively
positional arguments:
PATH Files or directories to fix
optional arguments:
-h, --help show this help message and exit
-i, --in-place Edit the files in-place. (default: False)
--version Show removestar version number and exit.
--no-skip-init Don't skip __init__.py files (they are skipped by
default) (default: True)
--no-dynamic-importing
Don't dynamically import modules to determine the list
of names. This is required for star imports from
external modules and modules in the standard library.
(default: True)
-v, --verbose Print information about every imported name that is
replaced. (default: False)
-q, --quiet Don't print any warning messages. (default: False)
--max-line-length MAX_LINE_LENGTH
The maximum line length for replaced imports before
they are wrapped. Set to 0 to disable line wrapping.
(default: 100)
白名单星号导入
removestar
不会替换标记有允许星号导入的 Flake8 noqa
注释 的星号导入行(例如,F401
或 F403
)。
例如,此模块中的星号导入将被保留
from os import * # noqa: F401
from .b import * # noqa
def func(x):
return x + y
当前限制
-
假设星号导入只使用当前文件中的名称(例如,在
__init__.py
中替换星号导入将不起作用)。 -
对于同一模块内的文件,removestar 会静态地确定缺失的导入名称。对于外部库导入,包括标准库模块的导入,它会动态导入模块以确定名称。可以使用
--no-dynamic-importing
标志禁用此功能。
贡献
请参阅 问题跟踪器。欢迎提交拉取请求。
变更日志
请参阅 CHANGELOG 文件。
许可
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。