Domanda

Supponiamo che io devo creare il mio piccolo DSL che avrebbe utilizzato Python per descrivere una certa struttura di dati. Per esempio. Mi piacerebbe essere in grado di scrivere qualcosa come

f(x) = some_stuff(a,b,c)

e hanno Python, invece di lamentarsi identificatori non dichiarati o il tentativo di richiamare la funzione some_stuff, convertirlo in un'espressione letterale per la mia ulteriore convenienza.

E 'possibile ottenere una ragionevole approssimazione a questo creando una classe con metodi __getattr__ e __setattr__ adeguatamente ridefinite e usarlo come segue:

e = Expression()
e.f[e.x] = e.some_stuff(e.a, e.b, e.c)

Sarebbe bello, però, se fosse possibile eliminare il fastidioso "e." prefissi e forse anche evitare l'uso di []. Quindi mi chiedevo, è possibile in qualche modo temporaneamente "ridefinire" ricerche di nomi globali e le assegnazioni? In una nota correlata, forse ci sono buoni pacchetti per raggiungere facilmente tale "citando" funzionalità per le espressioni Python?

È stato utile?

Soluzione

Non sono sicuro che sia una buona idea, ma ho pensato di fare un tentativo . Per riassumere:

class PermissiveDict(dict):
    default = None

    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            return self.default

def exec_with_default(code, default=None):
    ns = PermissiveDict()
    ns.default = default
    exec code in ns
    return ns

Altri suggerimenti

Si potrebbe voler dare un'occhiata ai moduli ast o parser inclusi con Python per analizzare, l'accesso e trasformare l'albero di sintassi astratta (o albero sintattico, rispettivamente) del codice di ingresso. Per quanto ne so, il Sage matematica sistema, scritto in Python, ha una simile sorta di pre-compilatore.

In risposta al commento di Wai, ecco una soluzione divertente che ho trovato. Prima di tutto, per spiegare ancora una volta quello che fa, si supponga di avere il seguente codice:

definitions = Structure()
definitions.add_definition('f[x]', 'x*2')
definitions.add_definition('f[z]', 'some_function(z)')
definitions.add_definition('g.i', 'some_object[i].method(param=value)')

in cui l'aggiunta di definizioni implica l'analisi dei fianchi mano sinistra e la mano destra lati e facendo altre cose brutte. Ora, uno (non necessariamente buono, ma certamente divertente) L'approccio qui permetterebbe di scrivere il codice precedente come segue:

@my_dsl
def definitions():
    f[x] = x*2
    f[z] = some_function(z)
    g.i  = some_object[i].method(param=value)

e hanno Python fare la maggior parte del parsing sotto il cofano. L'idea si basa sul semplice dichiarazione exec <code> in <environment>, menzionato da Ian, con un'aggiunta hacker. Vale a dire, il bytecode della funzione deve essere leggermente modificato e tutte le operazioni di accesso variabile locale (LOAD_FAST) commutato accesso variabile dall'ambiente (LOAD_NAME).

E 'più facile di quanto mostrato spiegato: http://fouryears.eu/wp-content / uploads / pydsl /

Ci sono vari trucchi si consiglia di fare per renderlo pratico. Ad esempio, nel codice presentato al link qui sopra non è possibile usare le funzioni built-in e costruzioni linguistiche, come i cicli for e se istruzioni all'interno di una funzione di @my_dsl. È possibile effettuare quelle lavoro, tuttavia, con l'aggiunta di un comportamento più alla classe Env.

Aggiorna . Qui è un po 'più dettagliata spiegazione della stessa cosa .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top