Domanda

Di recente ho scoperto metaclassi in Python.

Fondamentalmente una metaclasse in Python è una classe che crea una classe. Ci sono molte ragioni utili per cui vorresti fare questo, ad esempio qualsiasi tipo di inizializzazione di classe. Registrare classi su fabbriche, convalida complessa di attributi, alterare il funzionamento dell'ereditarietà, ecc. Tutto ciò diventa non solo possibile ma semplice.

Ma in Python, anche i metaclassi sono semplici classi. Quindi, ho iniziato a chiedermi se l'astrazione potesse utilmente andare più in alto, e mi sembra che possa e che:

  • una metaclasse corrisponde o implementa un ruolo in uno schema (come nei linguaggi dello schema GOF).
  • una meta-metaclasse è il modello stesso (se gli permettiamo di creare tuple di classi che rappresentano ruoli astratti, piuttosto che una sola classe)
  • una meta-meta-metaclasse è una fabbrica di modelli , che corrisponde ai raggruppamenti di modelli GOF, ad es. Creazionale, strutturale, comportamentale. Una fabbrica in cui potresti descrivere un caso di un certo tipo di problema e ti darebbe una serie di classi che lo hanno risolto.
  • una meta-meta-meta-metaclasse (per quanto potrei andare), è una fabbrica di fabbriche di modelli , una fabbrica alla quale potresti forse descrivere il tipo del tuo problema e darebbe sei una fabbrica di modelli da chiedere.

Ho trovato alcune cose su questo online, ma per lo più non molto utili. Un problema è che lingue diverse definiscono i metaclassi in modo leggermente diverso.

Qualcun altro ha usato metaclassi come questo in Python / altrove, o l'ha visto usato in natura o ci ha pensato? Quali sono gli analoghi in altre lingue? Per esempio. in C ++ fino a che punto può arrivare la ricorsione del modello?

Mi piacerebbe molto approfondire la ricerca.

È stato utile?

Soluzione

Il sistema di classi in Smalltalk è interessante da studiare. In Smalltalk, tutto è un oggetto e ogni oggetto ha una classe. Ciò non implica che la gerarchia vada all'infinito. Se ricordo bene, va qualcosa del tipo:

5 - > Numero intero - > Classe intera - > Metaclasse - > Classe metaclasse - > Metaclasse - > ... (loop)

Dove '- >' indica " è un'istanza di " ;.

Altri suggerimenti

Questo mi ricorda l'eterna ricerca su cui alcune persone sembrano impegnarsi per realizzare un'implementazione generica di un modello. Come una fabbrica che può creare qualsiasi oggetto ( inclusa un'altra fabbrica ), oppure un framework di iniezione di dipendenza per scopi generici che è molto più complesso da gestire rispetto alla semplice scrittura di codice che in realtà fa qualcosa

Ho avuto a che fare con persone intenzionate all'astrazione fino al punto di guardare l'ombelico mentre gestivo il progetto Zend Framework. Ho rifiutato una serie di proposte per creare componenti che non facevano nulla, erano solo implementazioni magiche dei modelli GoF, come se il modello fosse un obiettivo in sé, anziché un mezzo per un obiettivo.

C'è un punto di rendimenti decrescenti per l'astrazione. Qualche astrazione è fantastica, ma alla fine devi scrivere codice che faccia qualcosa di utile.

Altrimenti sono solo tartarughe fino in fondo .

Per rispondere alla tua domanda: no.

Sentiti libero di fare ulteriori ricerche.

Nota, tuttavia, che hai unito i modelli di progettazione (che sono solo idee) con il codice (che è un'implementazione.)

Un buon codice riflette spesso una serie di schemi di progettazione ad incastro. Non esiste un modo semplice per formalizzare questo. Il meglio che puoi fare è una bella foto, dotstrings ben scritti e nomi di metodi che riflettono i vari modelli di progettazione.

Nota anche che una meta-classe è una classe. Questo è un ciclo. Non esiste un livello più elevato di astrazioni. A quel punto, è solo intento. L'idea di meta-meta-classe non significa molto: è una meta-classe per meta-classi, che è sciocca ma tecnicamente possibile. È tutto solo un corso, tuttavia.


Modifica

" Le classi che creano metaclassi sono davvero così sciocche? Come si esaurisce improvvisamente la loro utilità? & Quot;

Una classe che crea una classe va bene. È praticamente tutto. Il fatto che la classe target sia una metaclasse o una superclasse astratta o una classe concreta non ha importanza. I metaclassi fanno lezioni. Potrebbero creare altri metaclassi, il che è strano, ma sono ancora solo metaclassi che fanno lezioni.

L'utilità "improvvisamente" si esaurisce perché non c'è nulla di reale (o addirittura possibile scrivere) necessario in una metaclasse che crea un'altra metaclasse. Non è che "all'improvviso" diventa sciocco. È che non c'è nulla di utile lì.

Mentre semino, sentiti libero di ricercarlo. Ad esempio, effettivamente scrivere una metaclasse che crea un'altra metaclasse. Divertiti. Potrebbe esserci qualcosa di utile lì.

Il punto di OO è scrivere definizioni di classe che modellano entità del mondo reale. Come tale, una metaclasse è talvolta utile per definire aspetti trasversali di diverse classi correlate. (È un modo per fare un po 'di programmazione orientata all'aspetto.) È tutto ciò che una metaclasse può davvero fare; è un posto dove tenere alcune funzioni, come __new __ () , che non sono parti proprie della classe stessa.

Durante la conferenza sulla storia dei linguaggi di programmazione del 2007, Simon Peyton Jones ha commentato che Haskell consente la meta-programmazione usando le classi di tipo, ma che in realtà è completamente tartaruga. Puoi programmare meta-meta-meta-meta ecc in Haskell, ma non ha mai sentito parlare di nessuno che utilizza più di 3 livelli di indiretta.

Guy Steele ha sottolineato che è la stessa cosa in Lisp e Scheme. Puoi fare meta-programmazione usando backtick ed eval (puoi pensare a un backtick come a Python lambda, un po '), ma non ha mai visto più di 3 backtick usati.

Presumibilmente hanno visto più codice di quanto tu o io abbia mai fatto, quindi è solo una leggera esagerazione dire che nessuno è mai andato oltre i 3 livelli di meta.

Se ci pensi, la maggior parte delle persone non usa mai la meta-programmazione e due livelli è piuttosto difficile da avvolgere. Immagino che tre siano quasi impossibili e che l'ultimo a provarne quattro sia finito in un manicomio.

Da quando ho capito per la prima volta le metaclassi in Python, ho continuato a chiedermi "cosa si potrebbe fare con una classe meta-meta?". Questo è successo almeno 10 anni fa - e ora, solo un paio di mesi fa, è diventato chiaro per me che esiste un meccanismo nella creazione della classe Python che coinvolge in realtà un "meta-meta"; classe. E quindi, è possibile provare a immaginarne un uso.

Ricapitolando l'istanza dell'oggetto in Python: Ogni volta che si crea un'istanza di un oggetto in Python mediante "quotando" la sua classe con la stessa sintassi usata per chiamare una normale funzione, il __new__ e il __init__ della classe. Cosa " orchestra " la chiamata di questi metodi sulla classe è esattamente il metodo __call__ class'metaclass '. Di solito quando si scrive una metaclasse in Python, viene personalizzato il metodo __new__ o __init__ della metaclasse.

Quindi, si scopre che scrivendo un " meta-meta " la classe uno può personalizzare il suo metodo __call__ e quindi controllare quali parametri vengono passati e ai metodi __new__ e __init__ della metaclasse e se qualche altro codice è essere chiamato prima di dopo quelli. Alla fine si scopre che i metcalse stessi sono di solito codificati in modo rigido e sono necessari solo alcuni, se del caso, anche in progetti molto grandi. Pertanto, qualsiasi personalizzazione che potrebbe essere effettuata nella sezione "meta meta" la chiamata viene solitamente eseguita direttamente sulla metaclasse stessa.

E poi, ci sono quegli altri usi meno frequenti per le metaclasse di Python: si può personalizzare un metodo __add__ in una metaclasse in modo che le classi che definiscono siano "addable" e creino una classe derivata avendo le due classi aggiunte come superclassi. Questo meccanismo è perfettamente valido anche con i metaclassi - quindi, quindi solo "abbiamo un po 'di codice reale", segue un esempio di "meta-meta" classe che consente di comporre "metaclass" per una classe semplicemente aggiungendoli alla dichiarazione di classe:

class MM(type):
    def __add__(cls, other):
        metacls = cls.__class__
        return metacls(cls.__name__ + other.__name__, (cls, other), {})

class M1(type, metaclass=MM):
    def __new__(metacls, name, bases, namespace):
        namespace["M1"] = "here"
        print("At M1 creation")
        return super().__new__(metacls, name, bases, namespace)

class M2(type, metaclass=MM):
    def __new__(metacls, name, bases, namespace):
        namespace["M2"] = "there"
        print("At M2 creation")
        return super().__new__(metacls, name, bases, namespace)

E possiamo vedere che funziona sulla console interattiva:

In [22]: class Base(metaclass = M1 + M2): 
    ...:     pass
    ...: 
At M1 creation
At M2 creation

Si noti che poiché diverse metaclasse in Python sono generalmente difficili da combinare, ciò può effettivamente essere utile consentendo a una metaclasse creata dall'utente di essere combinata con una libreria o una stdlib, senza che questa debba essere dichiarata esplicitamente come genitore del ex:

In [23]: import abc

In [24]: class Combined(metaclass=M1 + abc.ABCMeta):
    ...:     pass
    ...: 
At M1 creation
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top