我建議你看一看標準ast
模塊。下面是一些瑣碎的代碼:
import ast
source = '''
x=1
if not x:
print('not x')
'''
tree = ast.parse(source)
print(ast.dump(tree))
,這裏是輸出:
$ python test.py
Module(body=[Assign(targets=[Name(id='x', ctx=Store())], value=Num(n=1)), If(test=UnaryOp(op=Not(), operand=Name(id='x', ctx=Load())), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Str(s='not x')], keywords=[]))], orelse=[])])
禮Bendersky已與AST的工作寫了一個article,他包括一些示例代碼訪問 AST的節點。你會想在你尋找特定結構的地方進行一次訪問。在上面的例子中,你會尋找其中的操作數或者直接當作一個布爾值,或者作爲唯一的操作數到Not()
節點處理的If
節點下(子)的表達。
尋找每一個可能的案例可能會非常複雜。但我認爲你可以很容易地找到一個或兩個代碼的「簡單」情況(如果x,如果不是x,如果x或y)。
編輯:這裏有一些代碼(我認爲)做你想做的。
import ast
source = '''#Line 1
x=1
y=2
if not x:
print('not x')
if y is None:
print('y is none')
while y or not x or (x < 1 and not y and x < 10):
print('x < 10')
x += 1
'''
tree = ast.parse(source)
class FindNameAsBoolean(ast.NodeVisitor):
def __init__(self, lines):
self.source_lines = lines
def report_find(self, kind, locn, size=3):
print("\nFound %s at %s" % (kind, locn))
print(self.source_lines[locn[0]-1])
print(' ' * locn[1], '^' * size, sep='')
def visit_UnaryOp(self, node):
if isinstance(node.op, ast.Not) and isinstance(node.operand, ast.Name):
self.report_find('NOT-NAME', (node.lineno, node.col_offset), size=4 + len(node.operand.id))
self.generic_visit(node)
def visit_BoolOp(self, node):
opname = type(node.op).__name__.upper()
for kid in node.values:
if isinstance(kid, ast.Name):
self.report_find('%s-NAME' % opname, (node.lineno, node.col_offset), size=len(kid.id))
self.generic_visit(node)
class FindTests(ast.NodeVisitor):
def __init__(self, lines):
self.source_lines = lines
def _fnab(self, node):
cond = node.test
FindNameAsBoolean(self.source_lines).visit(cond)
def visit_If(self, node):
self._fnab(node)
self.generic_visit(node)
def visit_While(self, node):
self._fnab(node)
self.generic_visit(node)
FindTests(source.splitlines()).visit(tree)
而這裏的輸出:
$ python test.py
Found NOT-NAME at (5, 3)
if not x:
^^^^^
Found OR-NAME at (12, 6)
while y or not x or (x < 1 and not y and x < 10):
^
Found NOT-NAME at (12, 11)
while y or not x or (x < 1 and not y and x < 10):
^^^^^
Found NOT-NAME at (12, 31)
while y or not x or (x < 1 and not y and x < 10):
^^^^^
您知道'x或y'是一種混合型 - 輸入*被評估爲布爾值,但完整表達式的*輸出*將是其中一個輸入(不是布爾值)。 –