Disassembler, Syntax Tree und Flow Graph
Python bietet mächtige Werkzeuge zur Analyse und Transformation von Code, insbesondere auf niedriger Ebene. In dieser Referenz betrachten wir drei wichtige Konzepte: den Disassembler, den Syntaxbaum (AST) und den Kontrollflussgraphen.
1 Disassembler mit dis
Das Modul dis zeigt die Bytecode-Instruktionen, die vom Python-Interpreter ausgeführt werden. Es ist nützlich zur Fehleranalyse, Optimierung und beim Verständnis, wie Python intern arbeitet.
1.1 Beispiel: Disassemblieren einer Funktion
import dis
def greet(name):
return 'Hello ' + name
# Ausgabe des Bytecodes
dis.dis(greet)
Erklärung:
dis.dis()zeigt die Bytecode-Instruktionen.- Man sieht z. B.
LOAD_CONST,LOAD_FAST,BINARY_ADD,RETURN_VALUE.
2 Syntax Tree (AST – Abstract Syntax Tree)
Das ast-Modul ermöglicht es, Python-Code als abstrakten Syntaxbaum zu analysieren und zu manipulieren. So kann man z. B. Programme transformieren oder statisch untersuchen.
2.1 Beispiel: AST eines Ausdrucks erzeugen
import ast
source_code = 'x + 2'
tree = ast.parse(source_code, mode='eval')
# AST-Struktur anzeigen
print(ast.dump(tree, indent=4))
Erklärung:
ast.parse()erzeugt den Syntaxbaum.ast.dump()gibt ihn als lesbare Struktur aus.- Ideal zur statischen Codeanalyse oder Code-Transformation.
2.2 Beispiel: AST eines Moduls mit Funktion
code = '''
def square(x):
return x * x
'''
parsed = ast.parse(code)
print(ast.dump(parsed, indent=4))
3 AST Traversierung mit NodeVisitor
Man kann mit ast.NodeVisitor eigene Besucher-Klassen schreiben, um gezielt über den Baum zu laufen.
class FunctionLister(ast.NodeVisitor):
def visit_FunctionDef(self, node):
print(f'Found function: {node.name}')
self.generic_visit(node)
tree = ast.parse('''
def hello(): pass
def goodbye(): pass
''')
FunctionLister().visit(tree)
Erklärung:
visit_FunctionDefwird bei jeder Funktionsdefinition aufgerufen.generic_visit()sorgt für rekursive Durchläufe.
4 AST-Modifikation mit NodeTransformer
Mit NodeTransformer kann man den AST direkt verändern:
class ConstFolder(ast.NodeTransformer):
def visit_BinOp(self, node):
self.generic_visit(node)
if (isinstance(node.left, ast.Constant) and
isinstance(node.right, ast.Constant)):
return ast.Constant(value=eval(compile(ast.Expression(node), '', 'eval')))
return node
tree = ast.parse('x = 2 + 3')
new_tree = ConstFolder().visit(tree)
print(ast.dump(new_tree, indent=4))
Erklärung:
- Diese Transformation ersetzt
2 + 3durch5. - Praktisch für Optimierungen.
5 Flow Graph / Kontrollflussgraph
Python bietet keine Standardbibliothek für Flow-Graphs, aber man kann z. B. bytecode, cfg, oder externe Tools wie pycfg oder astmonkey verwenden.
Ein einfacher Kontrollflussgraph kann durch manuelle Analyse des AST oder Bytecodes entstehen.
5.1 Beispiel: Kontrolle über Sprungbefehle im Bytecode
import dis
def conditional(x):
if x > 0:
return 'positive'
else:
return 'non-positive'
dis.dis(conditional)
Erklärung:
- Man erkennt
POP_JUMP_IF_FALSEund entsprechende Sprungziele. - Diese lassen sich zu einem Flow Graph zusammensetzen.
5.2 Tools für CFG-Visualisierung
Diese Tools erzeugen z. B. DOT-Dateien, aus denen mit Graphviz Diagramme generiert werden können.
6 Fazit
| Thema | Zweck |
|---|---|
dis | Analyse des Bytecodes |
ast | Strukturierte Analyse und Manipulation von Code |
| Flow Graph | Analyse von Kontrollstrukturen und Ablaufpfaden |
Diese Werkzeuge sind besonders nützlich für Debugging, Optimierung, Sicherheitsanalysen oder eigene Python-Compiler/Interpreter-Projekte.