سؤال

لقد قمت دائما بإعداد metaclasses شيء مثل هذا:

class SomeMetaClass(type):
    def __new__(cls, name, bases, dict):
        #do stuff here

لكني مرت للتو عبر metaclass تم تعريفه مثل هذا:

class SomeMetaClass(type):
    def __init__(self, name, bases, dict):
        #do stuff here

هل هناك أي سبب لتفضيل واحد على الآخر؟

تحديث: ضع في اعتبارك أنني أسأل عن استخدام __new__ و __init__ في metaclass. أنا أفهم بالفعل الفرق بينهما في فصل آخر. ولكن في metaclass، لا أستطيع استخدام __new__ لتنفيذ التخزين المؤقت ل __new__ يتم استدعاء فقط إنشاء الطبقة في metaclass.

هل كانت مفيدة؟

المحلول

إذا كنت ترغب في تغيير الدسم DCT قبل إنشاء الفصل، أو تغيير Tuple القواعد، يجب عليك استخدامها __new__. وبعد عبر الوقت __init__ يرى الحجج، وكائن الفصل موجود بالفعل. أيضا، عليك استخدام __new__ إذا كنت ترغب في إرجاع شيء آخر غير فئة تم إنشاؤها حديثا من النوع المعني.

من ناحية أخرى، بحلول الوقت __init__ يعمل، فئة موجودة. وبالتالي، يمكنك القيام بأشياء مثل إعطاء مرجع إلى الفئة التي تم إنشاؤها فقط إلى أحد الكائنات الأعضاء فيها.

يحرر: تغيير الصياغة لجعله أكثر وضوحا أنه عن طريق "كائن"، أقصد كائن الفصل.

نصائح أخرى

يمكنك أن ترى الكتابة الكاملة في المستندات الرسمية, ، ولكن أساسا، __new__ يسمى قبل يتم إنشاء الكائن الجديد (لغرض إنشاءه) و __init__ يسمى بعد يتم إنشاء الكائن الجديد (لغرض تهيئة ذلك).

استخدام __new__ يسمح الحيل مثل التخزين المؤقت كائن (دائما إرجاع نفس الكائن لنفس الوسائط بدلا من إنشاء مجموعات جديدة) أو إنتاج كائنات من فئة مختلفة من المطلوبة (تستخدم أحيانا لإرجاع الفئات الفئة الفرعية المطلوبة في بعض الأحيان). عموما، إلا إذا كنت تفعل شيئا غريبا جدا، __new__ هي من فائدة محدودة. إذا لم تكن بحاجة إلى استدعاء هذه الخداع، فإن العصا __init__.

يمكنك تنفيذ التخزين المؤقت. Person("Jack") قم دائما بإرجاع كائن جديد في المثال الثاني بينما يمكنك البحث عن مثيل موجود في المثال الأول __new__ (أو عدم إرجاع أي شيء إذا كنت تريد).

كما قيل، إذا كنت تنوي تغيير شيء مثل الفصول الأساسية أو السمات، فسيتعين عليك القيام بذلك __new__. وبعد نفس الشيء صحيح بالنسبة لل name من الفصل ولكن يبدو أن هناك خصوصية معها. عند التغيير name, ، لا ينشأ إلى __init__, ، على الرغم من، على سبيل المثال attr يكون.

لذلك سيكون لديك:

class Meta(type):
    def __new__(cls, name, bases, attr):
        name = "A_class_named_" + name
        return type.__new__(cls, name, bases, attr)

    def __init__(cls, name, bases, attr):
        print "I am still called '" + name + "' in init"
        return super(Meta, cls).__init__(name, bases, attr)

class A(object):
    __metaclass__ = Meta

print "Now I'm", A.__name__

مطبوعات

I am still called 'A' in init
Now I'm A_class_named_A

هذا مهم لمعرفة، إذا __init__ يدعو إلى metaclass السوبر الذي يفعل بعض السحر الإضافي. في هذه الحالة، يتعين على المرء تغيير الاسم مرة أخرى قبل الاتصال super.__init__.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top