Matt Layman

Prendiamo un po ‘ di “meta” sulla programmazione.

In che modo il programma Python(meglio conosciuto come interprete)”sa” come eseguire il tuo codice?Se sei nuovo alla programmazione, potrebbe sembrare magic.In fatto, sembra ancora come magia per meafter essere un professionalfor più di un decennio.

L’interprete Python non è magico(mi dispiace deluderti).Segue un insieme prevedibile di passaggi per tradurre il tuo codein istruzioni che una macchina può eseguire.

Ad un livello abbastanza alto,ecco cosa succede al tuo codice:

  1. Il codice viene analizzato (cioè diviso) in un elenco di pezzi solitamente chiamati token.Questi token sono basati su un insieme di regoleper cose che dovrebbero essere trattate in modo diverso.Ad esempio, la parola chiave if è un token diverso da un valore numerico come 42.
  2. L’elenco grezzo dei token è trasformatoper costruire un albero di sintassi astratto, AST,che è l’argomento che esploreremo di più in questo post.Un AST è una raccolta di nodiche sono collegati tra loro in base alla grammatica del linguaggio Python.Non preoccupatevi se questo non aveva senso nowsince faremo brillare più luce su di esso momentaneamente.
  3. Da un albero di sintassi astratto,l’interprete può produrre un formof instructionscalled bytecode di livello inferiore.Queste istruzioni sono cose come BINARY_ADD e sono pensate per essere molto generiche in modo che un computer possa eseguirle.
  4. Con le istruzioni bytecode disponibili,l’interprete può finalmente eseguire il codice.Il bytecode viene utilizzato per chiamare le funzioninel tuo sistema operativoche alla fine interagirà con una CPU e memoryper eseguire il programma.

Molti altri dettagli potrebbero rientrare in quella descrizione,ma questo è lo schizzo approssimativo di come i caratteri tipizzati vengono eseguiti dalle CPU del computer.

AST come strumenti di analisi

Quando il tuo codice sorgente viene trasformato in bytecode,è troppo tardi per capire molto su ciò che hai scritto.Bytecode è molto primitivoe molto sintonizzato per rendere l’interprete fast.In altre parole, bytecode è progettato per i computer rispetto alle persone.

D’altra parte,gli alberi di sintassi astratti hanno abbastanza informazioni strutturate al loro interno per renderli utili per conoscere il tuo codice.Gli ASTS non sono ancora molto amichevoli, ma sono più sensibili della rappresentazione del bytecode.

Poiché Python è un linguaggio “batterie incluse”, gli strumenti necessari per utilizzare AST sono integrati nella libreria standard.

Lo strumento principale per lavorare con ASTs è il modulo ast.Diamo un’occhiata a un esempio per vedere come funziona.

ast per esempio

Di seguito è riportato lo script Python di esempio che useremo.Questo script risponde alla domanda ” quali moduli sono stati importati?”

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

Questo codice fa un paio di cose importanti:

  1. Trasforma il testo di un file Python(in questo caso, il codice di esempio stesso)in un albero di sintassi astratto.
  2. Analizza l’AST per estrarne alcune informazioni.

È possibile eseguire questo codice come:

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

Trasformazione di AST

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

In due righe di codice,abbiamo letto di un file e creare un AST denominato tree.La funzioneast.parse rende questo un gioco da ragazzi!C’è una tonnellata che accade sotto il cofano di quella funzione che possiamo ignorare beatamente.

Con una chiamata di funzione,Python ha elaborato tutti i token, seguito tutte le regole del linguaggio e creato una struttura dati (cioè, un albero) contenente tutte le informazioni pertinenti per eseguire il codice.

Prima di andare avanti,prendiamoci un momento per considerare cos’è un albero.Gli alberi sono uno sviluppo di software di topicin molto profondoconsiderano questo un primerrather che una spiegazione esaustiva.

Un albero è un modo per contenere i daticome un insieme di “nodi” collegati da “bordi.”

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

In questo diagramma,A, B e C sono tutti nodie ci sono bordi che collegano A a B e A a C.

Un modo per rappresentare questo albero nel codice potrebbe essere:

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

Si noti chetree è in realtà un nodo!Quando lavoriamo con un albero,abbiamo davvero a che fare con una raccolta di nodi e la variabile ad albero è un riferimento al nodo “radice” (ad esempio,nodo A).Avendo questo tipo di struttura, possiamo controllare ogni nodo nell’alberoe agire.Lo facciamo visitando ogni nodo dell’alberoe elaborando i suoi dati.

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

Ora che abbiamo un’idea di cosa sia un albero,possiamo considerare quale sia la sezione successiva dello script di esempio.La struttura ad albero dell’albero della sintassi astratta Python è più coinvolta a causa del conteggio dei suoi nodie del tipo di dati memorizzati,ma l’idea principale di nodi e bordi è la stessa.

Analizza l’AST

Una volta che abbiamo l’albero,Analyzer segue il modello del visitatore che ho mostrato sopra per estrarre informazioni dall’albero.

Ho notato che un AST Python è più complesso del mio design di baseNode.Una differenza è che tiene traccia di vari tipi di nodi.Questo è doveast.NodeVisitor è utile.

ANodeVisitor può rispondere a qualsiasi tipo di nodoin Python AST.To visita un particolare tipo di nodo, dobbiamo implementare un metodoche assomiglia a visit_<node type>.

Il mio codice di esempio sta cercando di scopriresu imports.To ulteriori informazioni sulle importazioni, il codice estrae dai tipi di nodoImport eImportFrom.

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)

Questo codice prende il nome del modulo e lo memorizza in un elenco di statistiche.Mentre il codice non è di fantasia,ti mostra come interagire con i nodi AST.

Con la classeNodeVisitor definita,possiamo usarla per analizzare l’albero.

analyzer = Analyzer()analyzer.visit(tree)

Il metodo visit delegherà al metodo visit_<node type> quando tale tipo di nodo è incontratomentre attraversa la struttura ad albero.

Quindi, quali tipi di tipi di nodi ci sono?Puoi trovare l’elenco completo nella sezione Abstract Grammar della documentazione del modulo ast.Sinceramente, trovo che la documentazione sia un po ‘ difficile da assorbire.Si può avere più successby riferendosi ad una guida più esaustiva come theGreen Tree Snakes nodi guida.

Avvolgendo

Ormai,si spera di capire come:

  1. Costruire un AST dal codice sorgente Python.
  2. Fare analisi sull’AST utilizzando un NodeVisitor.

Penso che tu possa rispondere a molte domande interessanti sul tuo codice usando alberi di sintassi astratti.Domande come:

  • Quante variabili ho usato?
  • Quali sono le chiamate di funzione più comuni nel mio codice?
  • I miei moduli sono strettamente accoppiati tra loro?
  • Quali librerie di terze parti appaiono frequentemente in pacchetti diversi?

Ilast modulo non è probabilmente uno strumento che si raggiunge per molto often.In quelle volte che hai bisogno di ast, la sua API minima è abbastanza memorabilee puoi analizzare rapidamente il codice.

Se l’hai trovato utile,ti dispiacerebbe condividerlo su Twitteror il tuo sito di social media preferito?Mi piace chiacchierare con peopleabout questi tipi di topicsso sentitevi liberi di twittarmi a @ mblayman.

Scopri Python!

Puoi iscriverti alla mia newsletter insieme a 1.000+ altri sviluppatori per aiutarti a saperne di più su Django e Python.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.