Matt Layman

laten we een beetje “meta” over programmeren.

Hoe”weet” het Python-programma (beter bekend als de interpreter) hoe je je code moet uitvoeren?Als je nieuw bent in programmeren, lijkt het misschien magic.In sterker nog, het lijkt nog steeds magie om meer dan tien jaar professioneel te zijn.

De Python-interpreter is niet magisch(sorry dat ik je teleurstel).het volgt een voorspelbare set stappen om je code te vertalen naar instructies die een machine kan draaien.

op een vrij hoog niveau,hier is wat er gebeurt met uw code:

  1. de code wordt ontleed (dat wil zeggen, opgesplitst) in een lijst van stukken die gewoonlijk tokens worden genoemd.Deze tokens zijn gebaseerd op een set regels voor dingen die anders moeten worden behandeld.Bijvoorbeeld, het sleutelwoord if is een ander token dan een numerieke waarde zoals 42.
  2. de ruwe lijst van tokens is getransformeerd om een abstracte Syntaxisboom te bouwen, AST,wat het onderwerp is dat we meer zullen onderzoeken in dit bericht.Een AST is een verzameling nodesdie aan elkaar zijn gekoppeld op basis van de grammatica van de Pythontaal.Maak je geen zorgen als dat nergens op slaat nu, want we zullen er binnenkort meer licht op schijnen.
  3. van een abstracte syntaxisboom kan de interpreter een lagere vorm van instructies produceren die doortecode wordt genoemd.Deze instructies zijn dingen als BINARY_ADDen zijn bedoeld om zeer generiek te zijn zodat een computer ze kan draaien.
  4. met de bytecode instructies beschikbaar, kan de interpreter eindelijk je code uitvoeren.De bytecode wordt gebruikt om functies aan te roepen in uw besturingssysteem die uiteindelijk zal communiceren met een CPU en memoryom het programma uit te voeren.

veel meer details zouden in die beschrijving kunnen passen,maar dat is de ruwe schets van hoe getypte tekens worden uitgevoerd door Computer CPU ‘ s.

ASTs als analysetools

tegen de tijd dat uw broncode wordt omgezet in bytecode,is het te laat om veel begrip te krijgen over wat u schreef.Bytecode is zeer primitief en zeer afgestemd op het maken van de interpreter fast.In met andere woorden,bytecode is ontworpen voor computers over mensen.

aan de andere kant hebben abstracte syntaxisbomen voldoende gestructureerde informatie in zich om ze bruikbaar te maken voor het leren over je code.As ‘ s zijn nog steeds niet erg mensenvriendelijk,maar ze zijn verstandiger dan de bytecode representatie.

omdat Python een “batterijen meegeleverd” taal is, zijn de gereedschappen die je nodig hebt om ASTs te gebruiken ingebouwd in de standaard bibliotheek.

Het primaire hulpmiddel om met ASS te werken is de ast module.Laten we eens kijken naar een voorbeeld om te zien hoe dit werkt.

AST door voorbeeld

Hieronder is het voorbeeld Python script dat we zullen gebruiken.Dit script beantwoordt de vraag ” welke modules werden geïmporteerd?”

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()

deze code doet een paar belangrijke dingen:

  1. transformeert de tekst van een Python-bestand(in dit geval de voorbeeldcode zelf)in een abstracte syntaxisboom.
  2. analyseert de AST om er wat informatie uit te halen.

U kunt deze code uitvoeren als:

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

transformeren naar AST

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

In twee regels van code lezen we een bestand en maken een AST aan met de naam tree.De ast.parse functie maakt dit in een handomdraai!Er gebeurt een ton onder de motorkap van die functie die we zalig kunnen negeren.

met één functieaanroep verwerkte Python alle tokens,volgde alle regels van de taal en bouwde een gegevensstructuur (d.w.z., een boom) die alle relevante informatie bevat om de code uit te voeren.

voordat we verder gaan, laten we een moment nemen om te overwegen wat een boom is.Bomen zijn een zeer diepe topicin software ontwikkelingenzo beschouwen dit als een primerrather dan een uitputtende uitleg.

een boomstructuur is een manier om gegevens vast te houden als een verzameling” knooppunten “verbonden door” randen.”

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

in dit diagram zijn A,B en C alle nodes en zijn er randen die A verbinden met B en A met C.

een manier om deze boom in code weer te geven zou kunnen zijn:

class Node: def __init__(self, value): self.value = value self.children = tree = Node('A')tree.children.append(Node('B'))tree.children.append(Node('C'))

merk op dat de tree eigenlijk een knooppunt is!Als we met een boom werken,hebben we echt te maken met een verzameling knooppunten, en de boomvariabele is een verwijzing naar de “root” knooppunt(bijvoorbeeld knooppunt A).door deze structuur te hebben,kunnen we elk knooppunt in de boom controleren en actie ondernemen.Dat doen we door elke nodein de boom te bezoeken en de gegevens ervan te verwerken.

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 we een idee hebben van wat een boom is,kunnen we overwegen wat de volgende paragraaf van het voorbeeld script doet.De boomstructuur van de Python abstracte syntaxis boom is meer betrokken vanwege de telling van de nodes en het type gegevens opgeslagen,maar de kern idee van knooppunten en randen is hetzelfde.

analyseer de AST

zodra we de boom hebben,volgt deAnalyzer het bezoekerspatroon dat ik hierboven liet zien om informatie uit de boom te halen.

Ik merkte op dat een Python AST complexer is dan mijn basis Node ontwerp.Een verschil is dat het volgt verschillende soorten knooppunten.Dit is waar ast.NodeVisitor nuttig is.

A NodeVisitor kan reageren op elk type nodein de Python AST.To bezoek een bepaald type knooppunt, we moeten een methode implementeren die lijkt op visit_<node type>.

mijn voorbeeldcode probeert meer te weten te komen over imports.To leer meer over importeren, de code trekt uit deImport enImportFrom knooppunttypen.

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)

deze code neemt de naam van de module en slaat deze op in een lijst met statistieken.Hoewel de code is niet mooi, het laat je zien hoe om te interactmet AST knooppunten.

met de NodeVisitor klasse gedefinieerd,kunnen we het gebruiken om de boom te analyseren.

analyzer = Analyzer()analyzer.visit(tree)

de visit methode zal delegeren aan uw visit_<node type> methode wanneer dat type knooppunt wordt ontmoet tijdens het doorlopen door de boomstructuur.

dus, welke soorten knooppunttypen zijn er?U kunt de volledige lijst vinden in de abstract grammatica sectie van de ast module documentatie.Eerlijk gezegd vind ik die documentatie een beetje moeilijk te verwerken.U kunt meer succes hebben door te verwijzen naar een meer uitputtende gids zoals de groene boom slangen knooppunten gids.

het afbreken van

inmiddels begrijpt u hopelijk hoe u:

  1. Een AST van Python-broncode kunt bouwen.
  2. doe analyse op de AST met behulp van een NodeVisitor.

Ik denk dat u veel interessante vragen over uw code kunt beantwoorden door gebruik te maken van abstracte syntaxisbomen.Vragen als:

  • hoeveel variabelen heb ik gebruikt?
  • Wat zijn de meest voorkomende functieaanroepen in mijn code?
  • zijn mijn modules nauw aan elkaar gekoppeld?
  • welke bibliotheken van derden worden vaak weergegeven in verschillende pakketten?

de ast module is waarschijnlijk geen tool die u zeer goed kunt gebruiken often.In die keren dat je astnodig hebt,is de minimale API vrij memorabel en kun je code snel analyseren.

Als u dit nuttig vond,zou u het erg vinden om dit te delen op Twitterer of op uw favoriete sociale media site?Ik hou van chatten met mensenbout dit soort topicszo voel je vrij om me te twitteren op@mblayman.

leer meer over Python!

u kunt deelnemen aan mijn nieuwsbrief samen met meer dan 1.000 andere ontwikkelaars om u te helpen meer te leren over Django en Python.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.