كتابة أصناف وصفية مخصصة
استخدم __new__ و__init__ في الأصناف الوصفية لتخصيص إنشاء الفئات
كتابة أصناف وصفية مخصصة درس مجاني في Python Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Python Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Python Academy 4 دروس في المجموع.
التصريح عن صنف فوقي
مرّر metaclass=MyMeta في تعريف الصنف لاستخدام صنف فوقي مخصّص. ويجب أن يرث الصنف الفوقي من type.
class MyMeta(type):
pass
class Foo(metaclass=MyMeta):
pass
print(type(Foo)) # <class '__main__.MyMeta'>تجاوز __new__
ينشئ __new__(mcs, name, bases, namespace) كائن الصنف. استخدمه لتعديل مساحة الأسماء قبل إنشاء الصنف.
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) # Trueتجاوز __init__
يُنفَّذ __init__(cls, name, bases, namespace) بعد إنشاء الصنف. استخدمه للإعدادات اللاحقة للإنشاء، مثل التسجيل.
_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': ...}فرض عقود الواجهات
ارفع TypeError في __new__ إذا كانت الأساليب المطلوبة مفقودة من جسم الصنف.
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 عبر صنف فوقي
تجاوز __call__ في الصنف الفوقي لاعتراض إنشاء المثيلات وإعادة المثيل نفسه في كل مرة.
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()) # Trueإضافة الأساليب ديناميكيًا
أدخل أساليب مساعدة في كل صنف يستخدم الصنف الفوقي، من دون تعديل كل صنف على حدة.
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__ لمساحة أسماء مرتبة
تجاوز __prepare__ لتوفير تعيين مخصّص بصفته مساحة أسماء الصنف، مثلًا للحفاظ على ترتيب التعريف أو اكتشاف التكرارات.
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()حل تعارض الأصناف الفوقية
عندما تكون للأصناف الأساسية المتعددة أصناف فوقية مختلفة، تتطلب Python استخدام الصنف الفوقي الأكثر اشتقاقًا صراحةً، وإلا فسيُرفع خطأ تعارض.
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): passالصنف الفوقي مقابل __init_subclass__
يُعد __init_subclass__ أبسط لتسجيل الأصناف الفرعية والخطافات البسيطة، ولا يتطلب صنفًا فوقيًا.
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]تتبّع الوصول إلى السمات
تجاوز __getattribute__ في الصنف الفوقي لاعتراض الوصول إلى سمات الصنف، وليس المثيلات.
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: HOSTنمط جمع حقول ORM
تستخدم أطر ORM المشابهة لـ Django الأصناف الفوقية لجمع واصفات Field من جسم الصنف ووضعها في سجل _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'])تحقق سريع
في صنف فوقي مخصّص، ما الأسلوب الذي يُستدعى لإنشاء كائن الصنف نفسه، قبل __init__؟
مراجعة
تتجاوز الأصناف الفوقية المخصّصة __new__/__init__ للتحكم في إنشاء الأصناف: فرض العقود، وتسجيل الأصناف الفرعية تلقائيًا، وإدخال الأساليب، أو جمع واصفات الحقول. يُفضّل استخدام __init_subclass__ عند الحاجة إلى تسجيل بسيط.
الأسئلة الشائعة
هل درس «كتابة أصناف وصفية مخصصة» مجاني؟
نعم — نص درس «كتابة أصناف وصفية مخصصة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Python Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Python Academy 4 دروس في المجموع.
ماذا ستتعلم في «كتابة أصناف وصفية مخصصة»؟
استخدم __new__ و__init__ في الأصناف الوصفية لتخصيص إنشاء الفئات تتمرن على Python Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Python Academy؟
لا تُشترط خبرة سابقة. Python Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «كتابة أصناف وصفية مخصصة»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Python Academy هذا؟
نعم. كل درس في Python Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- كيفية إنشاء فئات Python
- كتابة أصناف وصفية مخصصة
- واصفات الخصائص: __get__ و__set__ و__delete__
- __slots__ وتحسين الذاكرة