2 回答

TA貢獻(xiàn)2016條經(jīng)驗(yàn) 獲得超9個(gè)贊
假定你的代碼中都沒(méi)有直接從locals()/globals()中獲取b的引用,那這還是比較容易的,下面給你舉個(gè)例子吧。
比如這段代碼:
from a import bb
你可以用python的compiler模塊去解析它:
import compilercompiler.parse('from a import b\nb')
得到的輸出為這段代碼的AST(abstract syntax tree)
Module(None, Stmt([From('a', [('b', None)], 0), Discard(Name('b'))]))
有了AST,你就可以很容易地去處理它了,為了更簡(jiǎn)單一點(diǎn),可以這樣:
import parserst = parser.suite('from a import b\nb') print parser.st2list(st)
輸出是:
[257, [267, [268, [269, [281, [283, [1, "from"], [288, [1, "a"]], [1, "import"], [286, [284, [1, "b"]]]]]], [4, ""]]], [267, [268, [269, [270, [327, [304, [305, [306, [307, [308, [310, [311, [312, [313, [314, [315, [316, [317, [318, [1, "b"]]]]]]]]]]]]]]]]]], [4, ""]], [0, ""]]
這就是一棵用list構(gòu)成的樹了,你要做的事情就是先序遍歷,遍歷的過(guò)程中用一個(gè)dict保存所有被import的name,遇到引用name的時(shí)候,記錄它是否出現(xiàn)過(guò),最后輸出dict中沒(méi)有出現(xiàn)過(guò)的name即可。
另外,如果有這樣的情況:
from a import bb = 123 #后續(xù)對(duì)b的引用與import的b無(wú)關(guān)
你也可以特殊處理一下賦值操作,檢查被賦值的name是否在dict中且沒(méi)有被引用過(guò)
,如果是,輸出它,從dict里刪除,然后繼續(xù)。
EDIT
補(bǔ)充一下,有以下這些import語(yǔ)句需要考慮:
//from Python/Include/graminit.h
#define import_stmt 281#define import_name 282#define import_from 283#define import_as_name 284#define import_as_names 286

TA貢獻(xiàn)1880條經(jīng)驗(yàn) 獲得超4個(gè)贊
樓主想要干的事情,在程序靜態(tài)分析中,被稱為DCE(無(wú)用代碼的刪除)。自己實(shí)現(xiàn)一個(gè)也不是不可以,不過(guò)如果急用的話就不太合適了。
現(xiàn)成的插件/庫(kù)也是有很多的。我用過(guò)一段時(shí)間的pyflakes,它是一個(gè)代碼檢查插件,不僅可以滿足樓主的要求,還有更多的功能。以樓主的代碼為例,
$ echo "from a import b" > test.py$ pyflakes test.pytest.py:1: 'b' imported but unused
大概就是這樣。
添加回答
舉報(bào)