2013-01-04 37 views
4

我有一堆簡單的腳本在Python用簡單的表達式[1],如:查找一個python源/腳本依賴

C = A+B 
D = C * 4 

我需要執行它們,但最重要的,我需要知道什麼是我依賴的對象;在前一種情況下,對象AB是外部依賴關係。例如。給我有一個變種原代碼調用,我想能夠:

deps = { "A" : 1 , "B": 2} 
exec source in deps 

所以這是絕對必要知道如何建立字典的DEP

我已經潛入ast Python模塊,但我不知道。


[1]簡單的數學聚合,在一定程度上for週期,僅此而已。

+1

我想你可能是頑皮的,趕上前幾NameErrors –

+0

我很調皮不提,我做的完全一樣@JakobBowyer建議;) – Giupo

+0

的AST是不夠的。如果沒有完整的AST,全名解析和嚴格的數據流分析,您將無法爲除了非常簡單的腳本之外的任何其他工作而工作。由於Python是一種動態語言,即使是嚴重的數據流分析也不能提供體面的答案。如果你願意限制你的「Python」代碼非常簡單,那麼你可以建立一個可靠的分析器。你的問題是你的用戶不會注意你要施加的限制。所以除非用戶只是你,否則你不可能獲得好的結果。 –

回答

3

您可以使用標準庫中的tokenize模塊對Python源代碼進行標記。這將允許您查找腳本中使用的所有變量名稱。

現在假設我們將一個「非依賴關係」定義爲緊接在=符號之前的任何變量名稱。然後,根據你的腳本代碼的簡單真的是(請參閱下面的注意事項),您可能能夠確定變量名不屬於非依賴這種方式:

import tokenize 
import io 
import token 
import collections 
import keyword 

kwset = set(keyword.kwlist) 
class Token(collections.namedtuple('Token', 'num val start end line')): 
    @property 
    def name(self): 
     return token.tok_name[self.num] 

source = ''' 
C = A+B 
D = C * 4 
''' 

lastname = None 
names = set() 
not_dep = set() 
for tok in tokenize.generate_tokens(io.BytesIO(source).readline): 
    tok = Token(*tok) 
    print(tok.name, tok.val) 
    if tok.name == 'NAME': 
     names.add(tok.val) 
     lastname = tok.val 
    if tok.name == 'OP' and tok.val == '=': 
     not_dep.add(lastname) 

print(names) 
# set(['A', 'C', 'B', 'D']) 
print(not_dep) 
# set(['C', 'D']) 

deps = dict.fromkeys(names - not_dep - kwset, 1) 
print(deps) 
# {'A': 1, 'B': 1} 

注意事項

  • 如果您的腳本包含不是簡單 分配等語句,然後names可能成爲填充不需要 變量名。例如,

    import numpy 
    

    既能'import''numpy'添加到集合names

  • 如果你的腳本包含一個分配,使得使用左手 側元組拆包,如

    E, F = 1, 2 
    

    然後上面的天真代碼將只承認F不是 依賴。

+0

非常感謝! ) 我想,如果讓我的同事用「變量」全部寫成大寫的腳本,而不是使用單行多重賦值,我可以使用它;) – Giupo

+1

或者說服你的同事編寫可運行的代碼,明確。一個函數也許? – unutbu

+0

此外,據'在deps' EXEC源而言,它並不重要,如果'deps'包含密鑰不屬於依賴變量名。無論如何,'source'都會重新定義它們。因此,例如,如果您通過生成隨機值以用於「deps」來進行缺陷測試,那麼如果您的依賴性定義過於寬泛,則可以。 – unutbu