lad os få lidt “meta” om programmering.
hvordan virker Python-programmet (bedre kendt som tolken)”ved”, hvordan du kører din kode?Hvis du er ny til programmering, kan det virke som magic.In faktum, det virker stadig som magi at være professionel i mere end et årti.Python-tolken er ikke magisk(undskyld at skuffe dig).det følger et forudsigeligt sæt trin for at oversætte din codeinto instruktioner, som en maskine kan køre.
på et ret højt niveau er her hvad der sker med din kode:
- koden analyseres (dvs.opdeles) i en liste over stykker,der normalt kaldes tokens.Disse tokens er baseret på et sæt reglerfor ting, der skal behandles forskelligt.For eksempel er nøgleordet
if
et andet token end en numerisk værdi som42
. - den rå liste over tokens er transformeretat opbygge et abstrakt Syntakstræ, AST,hvilket er emnet, vi vil udforske mere i dette indlæg.En AST er en samling af nodersom er knyttet sammenbaseret på grammatikken af Python-sproget.Bare rolig, hvis det ikke gav mening nuda vi vil skinne mere lys på det øjeblik.
- fra et abstrakt syntakstræ kan tolken producere et lavere niveau form af instruktionerkaldet bytecode.Disse instruktioner er ting som
BINARY_ADD
og er beregnet til at være meget generiskså en computer kan køre dem. - med de tilgængelige bytecode-instruktioner kan tolken endelig køre din kode.Bytekoden bruges til at ringe funktioneri dit operativsystemsom i sidste ende vil interagere med en CPU og hukommelseat køre programmet.
mange flere detaljer kunne passe ind i denne beskrivelse, men det er den grove skitse af, hvordan typede tegnudføres af computer CPU ‘ er.
AST ‘ er som analyseværktøjer
når din kildekode er omdannet til bytecode,er det for sent at få meget forståelseom hvad du skrev.Bytecode er meget primitivog meget indstillet til at gøre tolken fast.In andre ord,bytecode er designet til computere over mennesker.
på den anden side har abstrakte syntakstræer nok strukturerede oplysningerinden for demfor at gøre dem nyttige til at lære om din kode.AST ‘ er er stadig ikke meget folk venlige, men de er mere fornuftige end bytecode-repræsentationen.
fordi Python er et “batterier inkluderet” sprog,er de værktøjer, du skal bruge AST ‘ er, indbygget i standardbiblioteket.
det primære værktøj til at arbejde med AST ‘ er erast
modulet.Lad os se på et eksempel for at se, hvordan dette fungerer.
ast ved eksempel
nedenfor er eksemplet Python script, som vi vil bruge.Dette script svarer på spørgsmålet om ” hvilke moduler blev importeret?”
import astfrom pprint import pprintdef main():with open("ast_example.py", "r") as source:tree = ast.parse(source.read())
analyzer <span style="color:#f92672">=</span> Analyzer()analyzer<span style="color:#f92672">.</span>visit(tree)analyzer<span style="color:#f92672">.</span>report()
class Analyzer(ast.NodeVisitor):def init(self):self.stats = {“import”: , “from”: }
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">visit_Import</span>(self, node): <span style="color:#66d9ef">for</span> alias <span style="color:#f92672">in</span> node<span style="color:#f92672">.</span>names: self<span style="color:#f92672">.</span>stats<span style="color:#f92672">.</span>append(alias<span style="color:#f92672">.</span>name) self<span style="color:#f92672">.</span>generic_visit(node)<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">visit_ImportFrom</span>(self, node): <span style="color:#66d9ef">for</span> alias <span style="color:#f92672">in</span> node<span style="color:#f92672">.</span>names: self<span style="color:#f92672">.</span>stats<span style="color:#f92672">.</span>append(alias<span style="color:#f92672">.</span>name) self<span style="color:#f92672">.</span>generic_visit(node)<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">report</span>(self): pprint(self<span style="color:#f92672">.</span>stats)
if name == “main”:main()
denne kode gør et par vigtige ting:
- omdanner en Python-fils tekst(i dette tilfælde selve eksempelkoden)til et abstrakt syntakstræ.
- analyserer AST for at udtrække nogle oplysninger ud af det.
Du kan køre denne kode som:
$ python3 ast_example.py{'from': , 'import': }
Transform til AST
with open("ast_example.py", "r") as source: tree = ast.parse(source.read())
i to linjer kode læser vi en fil og opretter en AST med navnet tree
.Funktionenast.parse
gør dette til et øjeblik!Der sker et ton under hætten på den funktion, som vi lykkeligt kan ignorere.
Med et funktionsopkald behandlede Python alle tokens, fulgte alle sprogets regler og byggede en datastruktur (dvs., et træ) indeholdende alle relevante oplysningerat køre koden.
før vi går videre,lad os tage et øjeblik til at overveje, hvad et træ er.Træer er en meget dyb topicinprogramudviklingså betragt dette som en primersnarere end en udtømmende forklaring.
et træ er en måde at holde data påsom et sæt “noder” forbundet med “kanter.”
+-----+ | A | +-----+ / \ / \+-----+ +-----+| B | | C |+-----+ +-----+
i dette diagram er A,B og C alle knuderog der er kanter, der forbinder A til B og A til C.
en måde at repræsentere dette træ i kode kunne være:
class Node: def __init__(self, value): self.value = value self.children = tree = Node('A')tree.children.append(Node('B'))tree.children.append(Node('C'))
Bemærk attree
er faktisk en node!Når vi arbejder med et træ,har vi virkelig at gøre med en samling noder,og trævariablen er en henvisning til “rod” – noden(f.eks.Det gør vi ved at besøge hver nodei træet og behandle sine data.
def print_node_value(value): print(value)def visit(node, handle_node): handle_node(node.value) for child in node.children: visit(child, handle_node)# tree is from the previous example.visit(tree, print_node_value)# This should print:# A# B# C
nu hvor vi har en ide om,hvad et træ er, kan vi overveje, hvad det næste afsnitaf eksemplet script gør.Træstrukturenaf Python abstrakt syntaks træer mere involveretpå grund af antallet af sine noderog typen af data gemt,men kerneideen om noder og kanter er den samme.
analyser AST
Når vi har træet,følgerAnalyzer
det besøgsmønsterat jeg viste ovenforat udtrække information ud af træet.
Jeg bemærkede, at en Python AST er mere kompleksend min grundlæggendeNode
design.En forskel er, at den sporer forskellige typer noder.Det er her ast.NodeVisitor
er nyttigt.
A NodeVisitor
kan reagere på enhver form for nodei Python AST.To besøg en bestemt type node, vi skal implementere en metodeder ligner visit_<node type>
.
mit eksempel kode forsøger at finde ud afom imports.To Lær om import, koden trækker fraImport
ogImportFrom
node typer.
def visit_Import(self, node): for alias in node.names: self.stats.append(alias.name) self.generic_visit(node)def visit_ImportFrom(self, node): for alias in node.names: self.stats.append(alias.name) self.generic_visit(node)
denne kode tager navnet på moduletog gemmer deti en liste over statistikker.Selvom koden ikke er fancy,viser den dig, hvordan du interagerermed AST-noder.
medNodeVisitor
klasse defineret,kan vi bruge den til at analysere træet.
analyzer = Analyzer()analyzer.visit(tree)
visit
stødt påmens du krydser gennem træstrukturen.
så hvilke typer knudetyper er der?Du kan finde den fulde liste iabstrakt grammatik afsnitaf ast
moduldokumentation.Sandfærdigt finder jeg den dokumentation lidt svært at absorbere.Du har muligvis mere succesved at henvise til en mere udtømmende guide somgreen Tree Snakes Nodes guide.
indpakning
nu forstår du forhåbentlig,hvordan du:
- Byg en AST fra Python kildekode.
- gør analyse på AST ved hjælp af en
NodeVisitor
.
Jeg tror, du kan besvare mange interessante spørgsmålom din kodeved hjælp af abstrakte syntaks træer.Spørgsmål som:
- hvor mange variabler brugte jeg?
- hvad er de mest almindelige funktionsopkald i min kode?
- er mine moduler tæt koblet til hinanden?
- hvilke tredjepartsbiblioteker vises oftei forskellige pakker?
ast
modulet er sandsynligvis ikke et værktøjat du vil nå til meget often.In de gange, du har brug for ast
,dens minimale API er ret mindeværdigog du kan analysere kode hurtigt.
Hvis du fandt dette nyttigt,ville du have noget imod at dele dette på kvidre eller dit foretrukne sociale medieside?Jeg kan godt lide at chatte med folk om disse slags emner, så du er velkommen til at kvidre mig på@mblayman.
Lær om Python!
Du kan tilmelde dig mit nyhedsbrev sammen med 1.000+ andre udviklere for at hjælpe dig med at lære mere om Django og Python.