是否有IDE/实用程序来重构Python*导入以使用标准module.member语法?
我最近的任务是维护大量使用模块导入中的是否有IDE/实用程序来重构Python*导入以使用标准module.member语法?,python,syntax,ide,refactoring,readability,Python,Syntax,Ide,Refactoring,Readability,我最近的任务是维护大量使用模块导入中的* 这个代码库已经变得足够大,以至于导入冲突/命名模糊/“这个函数是从哪里来的,有八个导入的模块有一个同名?!”ism变得越来越普遍 向前看,我一直在使用显式成员(即,import module…module.object.function()使我所做的维护工作更具可读性 但我想知道:是否有一个IDE或实用程序能够将Python代码和重构*导入语句解析为模块导入语句,然后将完整的模块路径预先添加到该模块成员的所有引用中? 我们没有大量使用元编程/反射/检查/
*
这个代码库已经变得足够大,以至于导入冲突/命名模糊/“这个函数是从哪里来的,有八个导入的模块有一个同名?!”ism变得越来越普遍
向前看,我一直在使用显式成员(即,import module…module.object.function()
使我所做的维护工作更具可读性
但我想知道:是否有一个IDE或实用程序能够将Python代码和重构*导入语句解析为模块导入语句,然后将完整的模块路径预先添加到该模块成员的所有引用中?
我们没有大量使用元编程/反射/
检查
/monkeypatching,因此,如果预期的IDE/util在这些方面表现不佳,那也没关系。不是一个完美的解决方案,但我通常做的是:
*
导入优化导入
命令(ctrl+shift+o
)重新添加所有导入如果您想自己构建解决方案,请尝试以下提到的其他相关工具:
- 直接使用,这对于您的使用来说是非常低级的
- 与之合作可能会有很多您正在寻找的样板代码
- ,一个重构库(@Lucas Graf)
- 这是一个重构库
pylint中使用的库
pylint
是在ast
之上构建的一个非常好的工具,它已经能够告诉您代码中有来自somemodule import*语句的,以及告诉您哪些导入是不必要的
例如:
# next is what's on line 32
from re import *
这将导致:
W: 32,0: Wildcard import re
W: 32,0: Unused import finditer from wildcard import
W: 32,0: Unused import LOCALE from wildcard import
... # this is a long list ...
找到解决方案?
请注意,在上述输出中,pylint
给出了行号。这可能需要一些努力,但重构工具可以查看这些特定的警告、获取行号、导入模块并查看\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
列表,或者使用沙盒execfile()
语句查看模块的全局名称(是否有帮助?可能……)。使用\uuuuu all\uuuu
中的全局名称列表和pylint
抱怨的名称,您可以有两个set()
并继续获得差异。将具有通配符导入的行替换为特定导入。在一般情况下,您不能这样做。观察import random的module.py
;如果random.random()>0.5:x=1
。正如@phihag所指出的,对于一般情况,不可能解决这个问题。但是,应该为您提供一些构建块来编写自己的工具,并至少自动化重构中涉及的一些任务。另一个没有提到的有用的是Python重构库。您可以尝试的另一件事是用显式导入列表(来自模块导入x,y,z
)替换模块导入*
)中的,这样当出现名称错误时,您就可以知道遗漏了什么(或者更好的是,您可以使用类似于pyflakes
的东西来进行静态代码分析并告诉您)。一旦您从模块导入*
语句中删除,它就应该能够告诉您什么是未定义的。@Jeff这个难题有几个问题:1)如何获得x,y,z
的列表?如果它是一个很好的模块或包,那么它定义了\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。但如果不是呢?导入模块并查看其全局?无聊的。如果你想做一个纯粹的静态分析,那是行不通的(我认为应该是这样)。您可能必须构建并解析它。@LukasGraf valid points。通过执行以下操作,您实际上可以轻松获得模块导入内容的列表:old_globals=dict(globals());从模块导入*;打印[k代表k,v在dict(globals())中。如果k不在old_globals或old_globals[k]!=v]
,则打印项目(),但这需要实际加载模块。因此,这至少可以让您将numpy import*
中的行转换为numpy import x、y、z中的,但这不是(完全)自动的;)它将不可避免地无法识别错误,改变代码的行为,并引入一个微妙的、难以发现的错误。投票支持一个有用的实用解决方案,但正如@LukasGraf所说,它并不适用于所有情况。更令人担忧的是,它可能会改变上述边缘情况下的行为。一个通用的case实用程序,即使只是“静态”(即没有自我修改,inspect
ion,甚至是重装饰或反射)的case也是我想要的。目前正在玩ast
和CPython源代码,看看是否有任何东西可以轻易地被黑客攻击到一起。然而,信心很低。@ZacB:我过去也遇到过同样的问题,但我从来没有找到一个好的解决方案,而且它对我来说太复杂,无法自己构建(也就是说,花费太多时间)。如果您可以执行代码,则可以相对轻松地确定从某个模块导入的内容,但要使类似的内容正常工作,仍然需要大量工作。@ZacB:如果您要构建它,请使用检查导入:)仍在使用通用案例解决方案。当我把它弄到(至少)无害的程度时,我会咬它。