Ho un caso strano e insolito per le metaclassi in cui vorrei modificare lo __metaclass__
di una classe base dopo che è stato definito in modo che le sue sottoclassi utilizzino automaticamente il nuovo __metaclass__
. Ma che stranamente non funziona:Perché non posso modificare l'attributo __metaclass__ di una classe?
class MetaBase(type):
def __new__(cls, name, bases, attrs):
attrs["y"] = attrs["x"] + 1
return type.__new__(cls, name, bases, attrs)
class Foo(object):
__metaclass__ = MetaBase
x = 5
print (Foo.x, Foo.y) # prints (5, 6) as expected
class MetaSub(MetaBase):
def __new__(cls, name, bases, attrs):
attrs["x"] = 11
return MetaBase.__new__(cls, name, bases, attrs)
Foo.__metaclass__ = MetaSub
class Bar(Foo):
pass
print(Bar.x, Bar.y) # prints (5, 6) instead of (11, 12)
quello che sto facendo può benissimo essere imprudente/supportato/indefinito, ma non posso per la vita di me a capire come viene richiamato il vecchio metaclasse, e mi piacerebbe meno capire come sia possibile.
EDIT: Sulla base di una proposta fatta da jsbueno
, ho sostituito la linea Foo.__metaclass__ = MetaSub
con la seguente riga, che ha fatto esattamente quello che volevo:
Foo = type.__new__(MetaSub, "Foo", Foo.__bases__, dict(Foo.__dict__))
Grazie per il suggerimento, che non ha fatto esattamente quello che volevo, dal momento che voglio ancora sottoclassi di 'Foo' per avere il metaclasse, ma ho modificato la mia domanda per includere la soluzione che ha fatto ciò di cui avevo bisogno, in base al tuo suggerimento. –