تو کلاس متد __new__ در کلاس Singleton چه اتفاقی داره می افته؟

پرسیده شده
فعالیت 1249 روز پیش
دیده شده 1171 بار
3

سلااااااااااااااااااام

میخواستم بدونم تو کلاس متد __new__ در کلاس Singleton چه اتفاقی داره می افته؟ من این تیکه کد رو نمیفهمم.

class Singleton:

    @classmethod
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, 'instance'):
            cls.instance = super(*args, **kwargs)
        return cls.instance

 

فایل پیوست

محمدعلی رضا
محمدعلی رضا

26 آبان 99

2
حذف شده

سلااااااااااااااااااام :)

تو این متد ما حواسمون هست که بیشتر از یه ابجکت از کلاس مون ساخته نشه. در واقع دفعه اول که کلاس Singleton صدا زده بشه ما هیچ class attribute ای بنام instance نداریم پس یه ابجکت میسازیم از کلاس Singleton و ابجکتی که ساختیم رو داخل class attribute ای بنام instance ذخیره میکنیم و برمیگردونیشم. دفعه های بعد که کلاس Singleton صدا زده بشه دیگه ابجکت جدید ازش ساخته نمیشه و مقدار class attribute instance رو برمیگردونیم.

 

حالا خط به خط هم کد رو توضیح بدم.

خط ۴: ما داریم کلاس متد __new__ رو باز نویسی میکنیم. همونطور که میدونیم همه کلاس های پایتون از کلاس object ارث بری میکنن. و وقتی ما یه کلاس رو صدا میزنیم مثلا کلاس Singleton رو صدا میزنیم اول متد __new__ اجرا میشه که توش یه ابجکت از نوع Singleton ساخته میشه و برش میگردونه و بعد متد __init__ اجرا میشه که توش self مقدار دهی میشه و در واقع __init__ یه constructor هست.

خط ۵: ما چک میکنیم که cls که همون کلاس Singleton هست تو این خط، آیا method یا attribute ای بنام instance داره یا نه؟ اگر method یا attribute ای بنام instance نداشت. دستورات داخل شرط اجرا میشه.

خط ۶: یه attribute بنام instance اضافه میکنیم و توش نتیجه صدا زدن super با آرگومان هایی که بهش میدیم رو میریزیم. در واقع وقتی super رو تو این خط صدا میزنیم ۲ تا متد اجرا میشه. اول متد __new__ کلاس super که اینجا super همون object هست صدا زده میشه و یه ابجکت ساخته میشه و بعد متد __init__ کلاس Singleton اجرا میشه.

خط ۷: مقدار cls.instance رو برمیگردونیم که حتما توش یه ابجکت از Singleton هست.

 

امیدوارم تو این پاسخ به جواب تون رسیده باشید و دیگه کامل فهمیده باشید تو کد بالا چه اتفاقی داره می افته و فهیمده باشیدش. باز اگر سوالی داشتید تو همین تاپیک بپرسید.

فایل پیوست

محمدعلی رضا

توسط

محمدعلی رضا

26 آبان 99

حذف شده
سلام محمد جان دو تا سوال برام پیش میاد شما گفتی super که صدا زده میشه اشاره میکنه به متد __new__ از کلاس object که کارش ساخت object جدید است . این آبجکت جدید رو براساس چه کلاسی میسازه؟ کلاس singleton یا کلاس object ? چون شما میگی super اشاره میکنه به متد _new__ کلاس object ، این متد هم کارش ساخت کلاس جدید است . بعد دومین متدی که با صدا زدن super اجرا میشه چی هستش؟
Ahmad As

26 آبان 99

حذف شده
و یک سوال دیگر اینکه چرا __new__ رو از دکوریتور classmethod استفاده کردین؟
Ahmad As

26 آبان 99

2
حذف شده

پوریا یه پیاده سازی دیگه هم از Singleton نوشته بود که بنظرم خوب بود (من یه خورده اصلاحش کردم)، البته کامل مطمئن نیستم که پیاده سازی درستی باشه. اما داره درست کار میکنه و به قول گفتنی It works

class Singleton2:
    instance = None

    @classmethod
    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

    def __init__(self):
        print("init touched!")

البته من تو گوگل سرچ کردم python singleton design pattern و پیاده سازی های دیگه ای دیدم. اما بنظرم پیاده سازی استاد واقعا خیلی بهتره.

فایل پیوست

محمدعلی رضا

توسط

محمدعلی رضا

26 آبان 99

2
حذف شده

پاسخ اولی که دادم خط ۶ رو یه مقدار اشتباه توضیح داده بودم. اصلاح شده اش اینطور میشه:

خط ۶: یه attribute بنام instance اضافه میکنیم و توش نتیجه صدا زدن super با آرگومان هایی که بهش میدیم رو میریزیم. در واقع وقتی super رو تو این خط صدا میزنیم ۲ تا متد اجرا میشه. اول متد __new__ کلاس super که اینجا super همون object هست صدا زده میشه و یه ابجکت ساخته میشه و بعد متد __init__ کلاس super که اینجا super همون object هست صدا زده. یعنی 

 

جواب سوالهایی که به عنوان دیدگاه تو پاسخ اولم نوشتی:

جواب سوال ۱) ببین ارث بری چطور بود؟ وقتی کلاس Singleton از کلاس object ارث بری میکنه، تمام method ها و attribute هاش رو به ارث میبره. حالا چون ما __new__ رو بازنویسی کردیم وقتی داخل متد __new__ ای که برای Singleton هست super رو صدا میزنیم. اول متد __new__ کلاس super اجرا میشه و بعد متد __init__ کلاس super، که منظور از super باز همون object هست.

پس ابجکت جدید طبق کدی که داخل __new__ کلاس object هست ساخته میشه ولی نوعش از کلاس Singleton هست. و اگر از تابع type استفاده کنی برا تشخص نوع ابجکت نهایی میبینی که میگه نوعش Singleton هست.

 

جواب سوال ۲) این قسمت رو قبلا اشتباه گفته بودم که اول همین پاسخ اصلاح کردم.

 

جواب سوال ۳) ۲ تا دلیل داره، یک بخاطر اینکه ما داریم __new__ رو بازنویسی میکنیم و __new__ داخل کلاس object یک classmethod هست و دلیل دوم که مهم تره اینکه که وقتی متد __new__ صدا زده میشه هنوز ابجکتی ساخته نشده و چیزی بنام self نداریم. و اگر بخواهیم به عنوان متد عادی تعریفش کنیم باید اولین آرکومان مون self باشه.

 

بنظرم خونده این صفحه میتونه بهتون کمک کنه:

https://jfine-python-classes.readthedocs.io/en/latest/call-a-class.html

 

این پاسخ هم توضیحاتش خیلی خوبه:

https://stackoverflow.com/a/61698095

فایل پیوست

محمدعلی رضا

توسط

محمدعلی رضا

26 آبان 99

0
حذف شده

سلام مجدد
در اصل یعنی اگر بخواهیم بدون classmethod استفاده کنیم به این شکل میشود کدمون ؟

class Singleton:
    instance = None

    def __new__(self, *args, **kwargs):
        if self.instance is None:
            self.instance = super().__new__(self)
        return self.instance

    def __init__(self):
        print("init touched!")

این کد هم خروجی یکسانی میده
فقط فرقش اینه من از classmethod استفاده نکردم .

راستیتش هنوز متوجه نشدم چرا classmethod استفاده کردیم

 

خروجی کد بالا :

<__main__.Singleton object at 0x000001B4148BDC08>
<__main__.Singleton object at 0x000001B4148BDC08>
<__main__.Singleton object at 0x000001B4148BDC08>

فایل پیوست

Ahmad As

توسط

Ahmad As

26 آبان 99

1
حذف شده

اول یه حرفی که بالا زدم رو اصلاح کنم. (واقعا ببخشید :) من تو پاسخ سومی که تو این تاپیک دادم یه جا گفتم:

جواب سوال ۳) ۲ تا دلیل داره، یک بخاطر اینکه ما داریم __new__ رو بازنویسی میکنیم و __new__ داخل کلاس object یک classmethod هست و دلیل دوم که مهم تره اینکه که وقتی متد __new__ صدا زده میشه هنوز ابجکتی ساخته نشده و چیزی بنام self نداریم. و اگر بخواهیم به عنوان متد عادی تعریفش کنیم باید اولین آرکومان مون self باشه.

که اصلاح شدش میشه این:

جواب سوال ۳) ما داریم از classmethod استفاده میکنیم بخاطر اینکه که وقتی متد __new__ صدا زده میشه هنوز ابجکتی ساخته نشده و چیزی بنام self نداریم. و اگر بخواهیم به عنوان متد عادی تعریفش کنیم باید اولین آرکومان مون self باشه. (البته میتونیم از staticmethod هم استفاده کنیم. ولی چون داخل متد میخواهیم از cls استفاده کنیم بهتره classmethod بنویسیم.)

 

جواب سوال "در اصل یعنی اگر بخواهیم بدون classmethod استفاده کنیم به این شکل میشود کدمون ؟"

اینکه نوشتی کار میکنه اما مساله اینه که کد پوریا تو پاسخ دوم رو برداشتی و توش فقط بجای کلمه cls از self استفاده کردی تو این تیکه کدت منظور از self همون cls هست. اگر از PyCharm استفاده کنی موس رو ببری روی آرگومان اول متد یعنی self، میبینی بهت این پیام رو میده:

Usually first parameter of such methods is named 'cls' 

 

با خوندن اون حرفی که اول این پاسخ نوشتم و اصلاح کردم شاید بتونی بفهمی چرا اینجا از classmethod استفاده کردیم.

فایل پیوست

محمدعلی رضا

توسط

محمدعلی رضا

26 آبان 99