Metaklasy w Pythonie to klasy, które tworzą inne klasy. Jeśli klasa jest szablonem dla obiektów, to metaklasa jest szablonem do tworzenia klas. Dzięki nim można programowo określać, jak są tworzone i zmieniane klasy.
W Pythonie wszystko jest obiektem, w tym także klasy. Pozwala to na określenie logiki tworzenia, modyfikacji i kontroli klas na etapie ich generacji. Podobne mechanizmy były już używane w innych językach, ale w Pythonie zostały zrealizowane w sposób szczególnie prosty i elegancki dzięki mechanizmowi metaklas.
Czasami w dużych projektach klasy muszą być budowane według szczególnych zasad lub zawierać obowiązkowe metody, właściwości, lub być automatycznie modyfikowane podczas ich definiowania. Bez metaklas prowadziłoby to do duplikacji kodu i rozprzestrzeniania błędów.
Metaklasy pozwalają modyfikować tworzenie klas poprzez nadpisanie metod klasy type, takich jak new i init. Można automatycznie dodawać metody, właściwości, walidować strukturę, stosować refleksję.
class UpperAttrMeta(type): def __new__(cls, name, bases, dct): new_attrs = {} for key, value in dct.items(): if not key.startswith('__'): new_attrs[key.upper()] = value else: new_attrs[key] = value return super().__new__(cls, name, bases, new_attrs) class Foo(metaclass=UpperAttrMeta): bar = 'bip' print(hasattr(Foo, 'bar')) # False print(hasattr(Foo, 'BAR')) # True
metaclass w deklaracji klasyCzy można zmienić metaklasę instancji po utworzeniu klasy? Nie. Po utworzeniu klasy jej metaklasę można zmienić tylko poprzez ponowną generację samej klasy. Instancja używa metaklasy określonej w jej klasie.
Czym metaklasy różnią się od dekoratorów klas? Dekoratory klas mogą zmienić klasę już po jej utworzeniu, natomiast metaklasy zarządzają samym procesem tworzenia i mogą nawet zabronić tworzenia klasy lub zmienić jej klasy bazowe.
Czy każda klasa musi mieć własną metaklasę?
Nie. Zwykle używa się standardowego type, metaklasa jest potrzebna tylko wtedy, gdy konieczne jest naruszenie domyślnego zachowania.
Zalety:
Negatywne przypadki: Początkujący architekt zaczął używać metaklas do prostych zadań (na przykład autogeneracja str), zamiast dekoratorów. Zalety: opanował nowe narzędzie. Wady: obciążył zespół niepotrzebną magią, pojawiły się błędy.
Pozytywny przypadek: W skomplikowanej ORM użyto metaklasy do autogeneracji tabel na podstawie klas Pythona. Zalety: scentralizowana kontrola struktury, automatyczna aktualizacja mapowań. Wady: wymagana szczegółowa dokumentacja i szkolenie nowych członków zespołu.