هل هناك أي سبب لاختيار __new__ عبر __init__ عند تحديد metaclass؟
-
12-09-2019 - |
سؤال
لقد قمت دائما بإعداد 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__
.