GreatBahram
GreatBahram
خواندن ۳ دقیقه·۵ سال پیش

معرفی __new__

A gentle introduction to __new__
A gentle introduction to __new__

مقدمه

توی این قسمت، خیلی سریع و خلاصه می‌خوایم متد __new__ رو معرفی کنیم و به کاربردهای اون اشاره کنیم.

معرفی

برای ساخت یک Instance از کلاس دو متد اصلی هستند که اجرا می‌شن. هر کدوم هم کار متفاوتی انجام میدن.

  • متد __new__: این متد، که خیلی کمتر مطلب بهش پرداخته شده، قبل از __init__ اجرا میشه و معمولا اگر قصد انجام کار خاصی رو نداشته باشید، نیازی به نوشتن‌اش نیست.متدی هم هست که آبجکت رو می سازه. نکته آخر اینکه این متد به صورت پیش‌فرض Static method هست و نیاز هم داره که پارامتر اول اون همیشه cls باشه.
  • متد __init__: این که خیلی ممکن هست اون رو متد سازنده (Constructor) توی پایتون بدونند، واقعاً نقش‌اش initializer رو بر عهده داره .

حالا برای روشن شدن مطلب می‌ریم اولش static method رو تعریف کنیم و بعدش به خود متد __new__ می‌پردازیم.

معرفی Static Method

این مفهوم در مقابل مفهوم دیگه‌ای به اسم instance variable قرار می‌گیره. تو مثال زیر متد و attributeهای ما instance variable هستند.

کاری که کردیم این هست که یک instance از کلاس Math ساختیم و از تابع add استفاده کردیم. اما چی میشه اگر ازش Instance نسازیم و بخوایم ازش استفاده کنیم؟

خطا بالا داره میگه که انگار یک پارامتر کمتر به تابع add دادیم و بهمین خاطر معترض شده! بیایم instance رو دستی بهش پاس بدیم:

همم، پس اینجوری خوشحال‌تر شد. پس instance variableها بدون داشتن یک instance قابل استفاده نیستند.

اما می‌تونیم خوشحالی کلاس Math رو یک سطح هم بالاتر ببریم اگر کلا این متد رو جوری تعریف کنیم که نیاز به Instance ای نداشته باشه و امکان استفاده بدون ساخت Instance هم وجود داشته باشه.

اینجا با کمک دوست خوب‌مون staticmethod - که یک property ( یا به اصطلاح درست‌تر یک Descriptor) هست - به پایتون می‌گیم که نیازی نیست که instance اولین پارامتر ما باشه. در نتیجه بدون ساخت instance می‌تونیم ازش استفاده کنیم.

حالا چی مشه، اگر از اون یک Instance بسازیم؟ آیا باز هم قابل استفاده هست؟

به عنوان جمع‌بندی این بخش، ما به صراحتاً به پایتون گفتیم که این متد به صورت static method به کارش ادامه بده، اما بعضی توابع خاص (Magic methods) به صورت پیش‌فرض static method هستند، مثل __new__.

معرفی __new__

وقتی می‌گیم که __init__ تابع سازنده نیست به این خاطر هست که شما داخل __init__ به آبجکت دسترسی دارید. نشون به این نشون که:

همین نشون میده که انگار یک‌جای دیگه instance ما ساخته شده (چون پایتون خطا نداد که self وجود نداره!).

  • نکته اول: میشه اینجوری هم گفت که هرکجا instance ما ساخته میشه، دیگه امکان استفاده از self وجود نخواهد داشت.
  • نکته دوم: با توجه به نکته یک میشه فهمید چرا __new__ به صورت پیش‌فرض staticmethod هست.
  • نکته سوم: instanceها وقتی ساخته می‌شن که شما class رو call می‌کنید مثل Music('Disturbia').
  • وظیفه‌ی متد __new__ این هست که instance رو برگردونه اگر این متد چیزی رو برنگردونه متد __init__ هم اجرا نمیشه. و نهایتاً اینکه __new__ همه‌ی پارامتر‌هایی که شما به کلاس‌تون پاس می‌دید رو میبینه و بعلاوه یک چیزه اضافه‌تر که جلوتر می‌بینیم.

یک نمونه با هم ببینیم:

با توجه به خروجی بالا، میشه فهمید که cls همون‌ کلاسی هست که قرار از روی اون یک instance ساخته بشه و مابقی هم پارامتر‌هایی هستند که از ورودی دریافت کردیم. همون‌طور که گفتیم اگر چیزی داخل __new__ برنگردونیم (return)، متد __init__ اجرا نمیشه، در نتیجه توی مثال بالا سه خط آخر اصلا اجرا نشده‌اند.

اگر بخواهیم رفتار نرمال متد __new__ رو نشون بدیم چیزی شبیه پایین میشه:

اینجا چه اتفاقی رخ داده؟ ما از سوپرکلاس‌مون خواهش کردیم که به جای ما یک instance بسازه و همچنین به صورت dynamic یک attribute به instance تازه ساخته شده اضافه کردیم (created_at).

کاربردها

چه مواقعی نیاز داریم که __new__ رو override کنیم؟

جواب.

یک مثال عملی رو با هم ببینیم و بحث رو تموم کنیم. اگر با ایده‌ی Singleton آشنا باشید می‌دونید که هدف اون ساخت کلاسی هست که فقط امکان ساخت یک instance ازش وجود داشته باشه. برای پیاده‌سازی این مفهوم روش‌های مختلفی هست اما ما عمداً با کمک متد __new__ این مفهوم رو پیاده‌سازی می‌کنیم:

اینجا متد سازنده رو طوری تغییر دادیم که - عمداً - فقط بتونیم یک instance از کلاس‌مون بسازیم و هربار که تلاش کنیم چیز جدید بسازیم همون قبلی رو برگردونه.

اگر مثال یا تجربه شخصی استفاده از متد __new__ دارید اون رو حتماً با ما به اشتراک بذارید.

کلام آخر

امیدوارم که از این مطلب خوشتون اومده باشه و چیزی ازش یاد گرفته باشید، اگر این‌طور بوده حتما این مطلب با پایتون دوست‌های دیگه به اشتراک بذارید. فعلاً!





pythonnewoopconstructorinitializer
Pythonista, Free Software Enthusiast. GNU/Linux Master. Network Security Researcher. Son. Brother.
شاید از این پست‌ها خوشتان بیاید