Che cosa sono le metaclassi in Python

di Lorenzo Neri
19 visualizzazioni

Che cosa sono le metaclassi in Python? A che cosa servono? Lo scopriamo nelle righe di questo articolo!

Se stai affrontando la programmazione in Python, è altamente probabile che tu ti sia imbattuto nelle metaclassi o se vogliamo dirla in inglese le metaclasses.

Bene, in questo articolo avrò il piacere di farti scoprire che cosa sono le metaclasses in Python ma soprattutto a che cosa servono.

Metaclassi in Python: un inception

No tranquillo: non sto parlando del film, ma se devo darti una definizione terra-terra di che cosa sono le metaclassi beh… Eccola qua:

Le metaclassi in Python sono le classi di un’altra classe

cit. Leonardo Di Caprio

No, Di Caprio non si è espresso a riguardo, ma sì le metaclassi sono proprio questo: cerchiamo di andare oltre.

Se guardami le cose da un’altra prospettiva, se una classe, a prescindere da Python intendo in qualsiasi linguaggio, definisce come si comporta una sua istanza, beh… Una metaclasse definisce come una classe si comporta.

Troppo tecnichese, sì lo ammetto: cerchiamo di capire qualcosa di più.

In linea generale una metaclasse viene utilizzata come “class-factory.

Le metaclassi sono “fattorie di classi”: in che senso?

Permettimi di farti un esempio.

Quando crei un oggetto, ovviamente invocando il costruttore della classe in merito, Python crea una nuova classe. Come? Chiamando la sua metaclasse.

Quando lo statement class viene eseguito in questo processo, quello che fa Python è eseguire il corpo della classe come un pezzo di codice normale.

Arrivati a questo punto, il namespace che ne risulta (un dizionario), mantiene in memoria l’attributo della classe che dovrà creare.

In questo processo, la metaclasse è determinata come? Guardando la classe che dovrà creare in questo processo.

Detta in termini molto più semplici, le metaclassi in Python sono un modo per definire il tipo di una classe.

Per questo il discorso di “inception” fatto all’inizio. Ma andiamo oltre per capire ancora di più tutto quanto il discorso.

Cosa posso fare con una metaclasse in Python?

Chiarito il che cosa è una metaclasse, è giusto capire anche che cosa ci puoi fare.

Per esempio, puoi definire dei metodi nella metaclasse.

Questi metodi, che appartengono alla metaclasse, sono metodi che tu puoi chiamare senza avere un’istanza della classe da cui li hai presi!

Chiaramente però, non funzionano come se avessi in mano un’istanza della classe stessa.

Per intenderci se volessi invocare uno di questi metodi, dovresti farlo in questo modo:

metaclasse.__subclasses__()

E puoi usare anche gli altri metodi magici come “__add__”, “__iter__” e ovviamente “__getattr__”.

Ma prima di salutarti, permettimi di lasciarti un esempio completo che riassuma sia che cosa sono le metaclassi in Python, ma anche come funzionano con del codice.

def fai_qualcosa(f):
    """Decorator per cambiare il metodo 'metodo' method into '__metodo__'"""
    f.is_qualcosa = 1
    return f

class IlMiotipo(type):
    def __new__(mcls, name, bases, attrs):

        if name.startswith('None'):
            return None

        # Prendiamo gli attributi e vediamo se devono essere rinominati.
        newattrs = {}
        for attrname, attrvalue in attrs.iteritems():
            if getattr(attrvalue, 'is_qualcosa', 0):
                newattrs['__%s__' % attrname] = attrvalue
            else:
                newattrs[attrname] = attrvalue

        return super(IlMiotipo, mcls).__new__(mcls, name, bases, newattrs)

    def __init__(self, name, bases, attrs):
        super(IlMiotipo, self).__init__(name, bases, attrs)

        # classregistry.register(self, self.interfaces)
        print "Registriamo la classe %s." % self

    def __add__(self, other):
        class AutoClass(self, other):
            pass
        return AutoClass
        # Diversamente, per generare automaticamente il classname:
        # return type(self.__name__ + other.__name__, (self, other), {})

    def unregister(self):
        # classregistry.unregister(self)
        print "De-registro la classe %s." % self

class IlMioOggetto:
    __metaclass__ = IlMiotipo


class NoneSample(IlMioOggetto):
    pass

# Stamperà "NoneType None"
print type(NoneSample), repr(NoneSample)

class Esempio(IlMioOggetto):
    def __init__(self, value):
        self.value = value
    @fai_qualcosa
    def add(self, other):
        return self.__class__(self.value + other.value)

# De-registra la classe
Esempio.unregister()

inst = Esempio(10)
# Fallirà con un errore
#inst.unregister()

print inst + inst
class Parziale(IlMioOggetto):
    pass

ExampleSibling = Esempio + Parziale
# ExampleSibling è ora una subclasse sia di "Esempio" sia di "Parziale" anche se pensa di essere invocato come "AutoClass"
print ExampleSibling
print ExampleSibling.__mro__

Potrebbero interessarti

Lascia un commento

Questo sito potrebbe fare uso di cookie e siccome l'UE mi obbliga a fartelo presente, eccoti il classico banner dove puoi decidere come gestirli. Accetta Leggi di più