Menulis Metaclass Kustom
Gunakan __new__ dan __init__ dalam metaclass untuk menyesuaikan pembuatan class.
Menulis Metaclass Kustom adalah pelajaran Python Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Python Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Python Academy mencakup 4 pelajaran total.
Mendeklarasikan Metakelas
Teruskan metaclass=MyMeta dalam definisi kelas untuk menggunakan metakelas khusus. Metakelas tersebut harus mewarisi dari type.
class MyMeta(type):
pass
class Foo(metaclass=MyMeta):
pass
print(type(Foo)) # <class '__main__.MyMeta'>Menimpa __new__
__new__(mcs, name, bases, namespace) membuat objek kelas. Gunakan metode ini untuk mengubah ruang nama sebelum kelas dibuat.
class UpperAttrMeta(type):
def __new__(mcs, name, bases, namespace):
upper = {k.upper(): v for k, v in namespace.items()
if not k.startswith("_")}
return super().__new__(mcs, name, bases, {**namespace, **upper})
class Config(metaclass=UpperAttrMeta):
debug = True
print(Config.DEBUG) # TrueMenimpa __init__
__init__(cls, name, bases, namespace) dijalankan setelah kelas dibuat. Gunakan metode ini untuk penyiapan setelah pembuatan, seperti pendaftaran.
_registry = {}
class AutoRegisterMeta(type):
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
if bases: # skip the base class itself
_registry[name] = cls
class Handler(metaclass=AutoRegisterMeta): pass
class JSONHandler(Handler): pass
class XMLHandler(Handler): pass
print(_registry) # {'JSONHandler': ..., 'XMLHandler': ...}Menegakkan Kontrak Antarmuka
Bangkitkan TypeError dalam __new__ jika metode yang diwajibkan tidak ada dalam isi kelas.
class InterfaceMeta(type):
REQUIRED = frozenset({"process", "validate"})
def __new__(mcs, name, bases, ns):
if bases and not mcs.REQUIRED.issubset(ns):
missing = mcs.REQUIRED - ns.keys()
raise TypeError(f"{name} must define: {missing}")
return super().__new__(mcs, name, bases, ns)
class Worker(metaclass=InterfaceMeta):
def process(self): ...
def validate(self): ...Singleton melalui Metakelas
Timpa __call__ pada metakelas untuk mencegat pembuatan instans dan mengembalikan instans yang sama setiap kali.
class SingletonMeta(type):
_instances = {}
def __call__(cls, *a, **kw):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*a, **kw)
return cls._instances[cls]
class DB(metaclass=SingletonMeta):
pass
print(DB() is DB()) # TrueMenambahkan Metode Secara Dinamis
Sisipkan metode utilitas ke setiap kelas yang menggunakan metakelas tersebut tanpa mengubah setiap kelas secara individual.
class MethodInjectorMeta(type):
def __new__(mcs, name, bases, ns):
ns["describe"] = lambda self: f"I am {type(self).__name__}"
return super().__new__(mcs, name, bases, ns)
class Widget(metaclass=MethodInjectorMeta):
pass
print(Widget().describe()) # I am Widget__prepare__ untuk Ruang Nama Terurut
Timpa __prepare__ untuk menyediakan pemetaan khusus sebagai ruang nama kelas, misalnya untuk mempertahankan urutan definisi atau mendeteksi duplikat.
class NoDuplicatesMeta(type):
class _NS(dict):
def __setitem__(self, k, v):
if k in self and not k.startswith("_"):
raise ValueError(f"Duplicate attribute: {k}")
super().__setitem__(k, v)
@classmethod
def __prepare__(mcs, name, bases):
return mcs._NS()Penyelesaian Konflik Metakelas
Jika beberapa kelas dasar memiliki metakelas yang berbeda, Python mengharuskan metakelas yang paling spesifik digunakan secara eksplisit, atau akan memunculkan kesalahan konflik.
class MetaA(type): pass
class MetaB(type): pass
# class Bad(A, B): pass # TypeError: metaclass conflict
class MetaAB(MetaA, MetaB): pass # resolve manually
class A(metaclass=MetaA): pass
class B(metaclass=MetaB): pass
class Good(A, B, metaclass=MetaAB): passMetakelas vs __init_subclass__
Untuk pendaftaran subkelas dan kait sederhana, __init_subclass__ lebih sederhana dan tidak memerlukan metakelas.
class Base:
_registry = []
def __init_subclass__(cls, **kw):
super().__init_subclass__(**kw)
Base._registry.append(cls)
class ChildA(Base): pass
class ChildB(Base): pass
print(Base._registry) # [ChildA, ChildB]Melacak Akses Atribut
Timpa __getattribute__ pada metakelas untuk mencegat akses atribut pada kelas, bukan pada instans.
class TraceMeta(type):
def __getattribute__(cls, name):
val = super().__getattribute__(name)
if not name.startswith("_"):
print(f"Accessing class attr: {name}")
return val
class Config(metaclass=TraceMeta):
HOST = "localhost"
_ = Config.HOST # logs: Accessing class attr: HOSTPola Pengumpulan Field ORM
ORM bergaya Django menggunakan metakelas untuk mengumpulkan deskriptor Field dari isi kelas ke dalam registri _meta.
class Field:
def __init__(self, col): self.col = col
class ModelMeta(type):
def __new__(mcs, name, bases, ns):
fields = {k: v for k, v in ns.items() if isinstance(v, Field)}
ns["_fields"] = fields
return super().__new__(mcs, name, bases, ns)
class User(metaclass=ModelMeta):
name = Field("name")
email = Field("email")
print(User._fields.keys()) # dict_keys(['name', 'email'])Pemeriksaan Singkat
Dalam metakelas khusus, metode apa yang dipanggil untuk membuat objek kelas itu sendiri, sebelum __init__?
Ringkasan
Metakelas khusus menimpa __new__/__init__ untuk mengendalikan pembuatan kelas: menegakkan kontrak, mendaftarkan subkelas secara otomatis, menyisipkan metode, atau mengumpulkan deskriptor field. Lebih baik gunakan __init_subclass__ untuk kebutuhan pendaftaran sederhana.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Menulis Metaclass Kustom” gratis?
Ya — teks lengkap “Menulis Metaclass Kustom” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Python Academy, upgrade ke CoddyKit PRO. Kursus Python Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Menulis Metaclass Kustom”?
Gunakan __new__ dan __init__ dalam metaclass untuk menyesuaikan pembuatan class. Kamu berlatih Python Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Python Academy?
Tidak diperlukan pengalaman sebelumnya. Python Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Menulis Metaclass Kustom” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Python Academy ini?
Ya. Setiap pelajaran Python Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Cara Class Python Dibuat
- Menulis Metaclass Kustom
- Descriptor: __get__, __set__, __delete__
- __slots__ dan Optimasi Memori