In programmazione a oggetti, una metaclasse è una classe le cui istanze sono a loro volta classi. Questo concetto è strettamente legato al concetto di riflessione (reflection), che si applica a quegli strumenti concettuali che permettono di rappresentare, all'interno di un programma, informazioni sulle parti costituenti del programma stesso (tipicamente classi e oggetti).
Il concetto di metaclasse è impiegato soprattutto a livello teorico (appare, per esempio, nella definizione formale della semantica dello Unified Modeling Language), ma trova anche applicazioni dirette in diversi linguaggi di programmazione. In Java, per esempio, tutte le classi sono concettualmente considerate istanze dell'unica metaclasse Class
, in Python type
è una metaclasse.
In Python una metaclasse è per lo più definita come una sottoclasse di type.
class AttributeInitType(type):
def __call__(self, *args, **kwargs):
""" Create a new instance. """
# First, create the object in the normal default way.
obj = type.__call__(self, *args)
# Additionally, set attributes on the new object.
for name, value in kwargs.items():
setattr(obj, name, value)
# Return the new object.
return obj
Questa metaclasse sovrascrive solamente la creazione dell'oggetto. Tutti gli altri aspetti della classe e comportamento dell'oggetto sono ancora gestiti da type. Ora la classe Car può essere riscritta per usare questa metaclasse. In Python 2 si fa assegnando __metaclass__ nella definizione di classe mentre in Python 3 fornendo all'argomento della classe metaclass = M)
class Car(object):
__metaclass__ = AttributeInitType
__slots__ = ['make', 'model', 'year', 'color']
@property
def description(self):
""" Return a description of this car. """
return "%s %s %s %s" % (self.color, self.year, self.make, self.model)
Gli oggetti Car
si possono istanziare così:
cars = [
Car(make='Toyota', model='Prius', year=2005, color='green'),
Car(make='Ford', model='Prefect', year=1979, color='blue')]
Un altro esempio di Metaclasse in Python:
class Spell(type):
def __new__(cls,classname,super,classdict):
def pph( hours ): return lambda self : self.pay_per_hour * hours
classdict['pay_per_hour'] = 12
classdict['day_salary'] = pph(8)
classdict['week_salary'] = pph(8*5)
classdict['year_salary'] = pph(8*5*4*12)
classdict['month_salary'] = pph(8*5*4)
return type.__new__(cls, classname, super, classdict )
class Person(metaclass=Spell):
def __init__(self,name,lastname,bday):
self.name = name
self.lastname = lastname
self.bday = bday
def get_name(self):
return self._name
def get_lastname(self):
return self._lastname
def get_bday(self):
return self._bday
def __repr__(self):
return "name: {0}, lastname: {1}, bday: {2}".format(self.name,self.lastname,self.bday)
if __name__ == "__main__":
persona = Person("Mario","Rossi","23 novembre 65")