Matt Layman

La oss få litt «meta» om programmering.

Hvordan Vet Python-programmet(bedre kjent som tolken) » hvordan du kjører koden din?Hvis du er ny til programmering, kan det virke som magic.In faktisk virker det fortsatt som magi for megetter å ha vært profesjonelli mer enn et tiår.

Python tolken er ikke magisk(beklager å skuffe deg). Det følger et forutsigbart sett med trinn for å oversette kodeintoinstruksjonene som en maskin kan kjøre.

på et ganske høyt nivå,her er hva som skjer med koden din:

  1. koden analyseres (dvs.delt opp) i en liste over stykker som vanligvis kalles tokens.Disse tokens er basert på et sett med reglerfor ting som bør behandles annerledes.For eksempel er søkeordet if et annet token enn en numerisk verdi som 42.
  2. den raske listen over tokens er transformertå bygge Et Abstrakt Syntakstre, AST, som er emnet vi vil utforske mer i dette innlegget.En AST er en samling av nodersom er koblet sammenbasert på grammatikkenav Python-språket.Ikke bekymre deg hvis det ikke ga mening nå, siden vi vil skinne mer lys på det et øyeblikk.
  3. fra en abstrakt syntaks treet,kan tolken produsere et lavere nivå formof instructionscalled bytecode.Disse instruksjonene er ting som BINARY_ADDog er ment å være veldig generiskslik at en datamaskin kan kjøre dem.
  4. med bytecode instruksjoner tilgjengelig,kan tolken endelig kjøre koden.Bytekoden brukes til å ringe funksjoneri operativsystemet dittsom til slutt vil samhandle MED EN CPU og minneå kjøre programmet.Mange flere detaljer kan passe inn i den beskrivelsen,men det er den grove skissen av hvordan typede tegn utføres av datamaskin-Cpuer.

    ASTs som analyseverktøy

    Når kildekoden din blir omgjort til bytekode, er det for sent å få mye forståelseom hva du skrev.Bytecode er veldig primitivog veldig innstilt på å gjøre tolken fast.In andre ord,bytecode er designet for datamaskiner over mennesker.på den annen side har abstrakte syntakstrær nok strukturert informasjoninnenfor demfor å gjøre dem nyttigefor å lære om koden din.ASTs er fortsatt ikke veldig vennlige, men de er mer fornuftige enn bytecode-representasjonen.

    Fordi Python er et» batterier inkludert » språk, er verktøyene du trenger for Å bruke ASTs innebygd i standardbiblioteket.

    det primære verktøyet for Å arbeide med ASTs erast modulen.La oss se på et eksempel for å se hvordan dette fungerer.

    ast ved eksempel

    Nedenfor Er Eksemplet Python script som vi skal bruke.Dette skriptet svarer på spørsmålet om » hvilke moduler ble importert?»

    import astfrom pprint import pprint

    def 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 koden Gjør et par store ting:

    1. Forvandler En Pythonfils tekst (i dette tilfellet selve eksempelkoden) til et abstrakt syntaxtre.
    2. Analyserer AST for å trekke ut litt informasjon ut av det.

    du kan kjøre denne koden som:

    $ python3 ast_example.py{'from': , 'import': }

    Transformere TIL AST

    with open("ast_example.py", "r") as source: tree = ast.parse(source.read())

    i to linjer med kode leser vi en fil og lager en ast som hetertreeast.parse funksjonen gjør dette enkelt!Det er massevis som skjer under hetten til den funksjonenat vi kan blissfully ignorere.

    Med ett funksjonskall behandlet Python alle tokens, fulgte alle språkets regler og bygget en datastruktur (dvs., et tre) som inneholder all relevant informasjonå kjøre koden.

    før vi går videre,la oss ta et øyeblikk å vurdere hva et tre er.Trær er et veldig dypt emnei programvareutviklingogså betrakt dette som en primerheller enn en uttømmende forklaring.

    et tre er en måte å holde data på som et sett med «noder» forbundet med » kanter.»

     +-----+ | A | +-----+ / \ / \+-----+ +-----+| B | | C |+-----+ +-----+

    I dette diagrammet Er A,B og c alle noderog det er kanter som forbinder A Til B Og A Til C.

    en måte å representere dette treet i kode kan 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'))

    Legg merke til at tree er faktisk en node!Når vi jobber med et tre,har vi virkelig å gjøre med en samling noder,og trevariabelen er en referanse til «rot» – noden(f.eks. node A). ved å ha denne typen struktur, kan vi sjekke hver node i treet og ta tiltak.Vi gjør det ved å besøke hver nodei treetog behandle dataene sine.

    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

    Nå som vi har en ide om hva et tre er,kan vi vurdere hva neste delav eksempelskriptet gjør.Trestrukturenav Python abstract syntax treeer mer involvedbecause av tellingen av noderog typen data lagret, men kjerneideen om noder og kanter er den samme.

    Analyser AST

    når vi har treet,følgerAnalyzer besøksmønstretsom jeg viste ovenforå trekke ut informasjon ut av treet.

    jeg bemerket at En Python AST er mer kompleks enn min grunnleggendeNode design.En forskjell er at den sporer ulike typer noder.Dette er hvorast.NodeVisitor er nyttig.

    A NodeVisitor kan svare på alle typer nodei Python AST.To besøk en bestemt type node, vi må implementere en metodesom ser ut som visit_<node type>.

    mitt eksempelkode prøver å finne utom imports.To lær om import, koden trekker fra nodetypeneImport ogImportFrom.

    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 koden tar navnet på modulenog lagrer deni en liste over statistikk.Selv om koden ikke er fancy, viser den deg hvordan du kan samhandle MED AST-noder.

    med NodeVisitor klassen definert,kan vi bruke den til å analysere treet.

    analyzer = Analyzer()analyzer.visit(tree)

    visitmetoden vil delegere tilvisit_<node type>metodenår denne typen node er encounteredwhile krysser gjennom trestrukturen.

    Så, hvilke typer nodetyper er der?Du finner hele listen iabstract Grammar sectionofast modul dokumentasjon.Sannferdig finner jeg den dokumentasjonen litt vanskelig å absorbere.Du kan ha mer suksessved å henvise til en mer uttømmende guide som theGreen Tree Snakes Nodes guide.

    Innpakning opp

    nå forstår du forhåpentligvis hvordan du:

    1. Bygg EN AST fra Python kildekode.
    2. gjør analyse på AST ved hjelp av en NodeVisitor.

    jeg tror du kan svare på mange interessante spørsmålom kodenved å bruke abstrakte syntakstrær.Spørsmål som:

    • Hvor mange variabler brukte jeg?
    • Hva er de vanligste funksjonsanropene i koden min?
    • er modulene mine tett koblet til hverandre?
    • hvilke tredjepartsbiblioteker dukker opp oftei forskjellige pakker?

    ast modulen er sannsynligvis ikke et verktøy som du vil nå for veldig often.In de gangene du trenger ast, er minimal API ganske memorableog du kan analysere kode raskt.

    hvis du fant dette nyttig, vil du dele dette På Twittereller ditt favoritt sosiale medier nettsted?Jeg liker å chatte med peopleabout slike emnerså gjerne tweet meg på@mblayman.

    Lær Om Python!

    du kan bli med på nyhetsbrevet mitt sammen med 1000 + andre utviklere for å hjelpe deg med å lære Mer Om Django og Python.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert.