💻 آخرین فرصت یادگیری برنامه‌نویسی با آفر ویژه قبل از افزایش قیمت در ۱۵ آذر ماه (🎁 به همراه یک هدیه ارزشمند )
۰ ثانیه
۰ دقیقه
۰ ساعت
۴ mehrdad sarani1
چرا super
جامعه پایتون (وب) ایجاد شده در ۰۶ آذر ۱۳۹۹

سلام

 

 ۱- چرا ما داریم با super شی می‌سازیم super به ابجکت super اشاره می‌کنه و نمی‌تونیم از magic method‌ها استفاده کنیم و Exception Raise میکنه چرا من زمانی که از خود cls(*args **kwargs) می‌خوام ابجکت بسازم بازم Exception می‌دهد حتی با Singleton هم نمی‌تونم instance بسازم

 

 

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

 

جواب سوال ۱) وقتی ما از super(*args, **kwargs) داخل متد __new__ کلاس Singleton استفاده میکنیم (کدی که تو این جلسه داشتیم.) متدهای __new__ و __init__ کلاس پدرش رو صدا میزنیم و از اون متدها برای ساخت ابجکت استفاده میکنیم که کلاس پدر همه کلاس‌های پایتونی object هست. و اگر از cls(*args **kwargs) استفاده کنیم برای ساخت ابجکت در واقع داریم متدهای __new__ و __init__ کلاس Singleton رو صدا میزنیم که با اینکار داریم تو یه حلقه بینهایت می‌افتیم. چون وقتی cls(*args **kwargs) یا کلاس Singleton رو برای ساخت ابجکت صدا میزنیم. اول وارد متد __new__ کلاس Singleton میشه و دوباره به این خط cls(*args **kwargs) میخوره که باز میره سراغ متد __new__ کلاس Singleton و این یه حلقه بینهایت هست و پایتون بعد کلی تکرار جلوش رو میگیره.

 

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

محمدعلی رضا ۰۶ آذر ۱۳۹۹، ۱۰:۳۳

بله خیلی ممنون مورد اول رو متوجه شدم توی یه loop میافته

ولی کلاس super یه آبجکت از super می‌سازه

که نمی‌شه به magic method‌ها دسترسی پیدا کرد بهت چرا نیست از static method استفاده کنیم و get instance رو انجام بدیم؟

mehrdad sarani1 ۰۶ آذر ۱۳۹۹، ۱۰:۴۹

نه این جمله ات درست نیست:

کلاس super یه آبجکت از super می‌سازه

ببین وقتی ما یه کلاس مثل Singleton رو صدا میزنم یه ابجکت ازش ساخته میشه و اون ابجکتی که ساخته رو برمیگردونه بهمون. در واقع وقتی یه کلاس مثل Singleton رو صدا میزنم:

Singleton(*argv, **kwargs)

1. میره دنبال تابع __new__ طبق MRO میگرده. بعد نتیجه کد زیر رو تو یه جایی ذخیره میکنه که ما اسمش رو tmp میذاریم فعلا:

Singleton.__new__(C, *argv, **kwargs)

2. بعد دنبال متد __init__ ابجکت tmp میگرده و نتیجه کد زیر رو به عنوان مقدار برگشتی از صدا زدن کلاس Singleton برمیگردونه:

self.__init__(*argv, **kwargs)

(نکته: اگر tmp ای که تو مرحله 1 ساخت type اش Singleton نباشه مرحله اصلا اجرا نمیشه.)

 

خب حالا برگردیم به اصل قضیه، وقتی ما super(*args, **kwargs) رو صدا میزنیم چه اتفاقی می‌افته؟

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

 

این جمله رو هم نمیدونم طبق چی گفتی:

که نمی‌شه به magic method‌ها دسترسی پیدا کرد

چون میشه و دسترسی داریم مثلا کد زیر هیچ مشکلی نداره:

class Singleton:
    @classmethod
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, 'instance'):
            cls.instance = super(*args, **kwargs)
        return cls.instance
s1 = Singleton()
print(s1.__class__)
print(s1.__hash__())
print(s1.__sizeof__())
print(s1.__str__())

 

مساله آخری که پرسیدی:

بهت چرا نیست از static method استفاده کنیم و get instance رو انجام بدیم؟

رو نمیدونم و از استاد رمضان پور میپرسم.

 

 

منابع:

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

محمدعلی رضا ۰۶ آذر ۱۳۹۹، ۱۶:۰۷

این سوالت رو از استاد رمضان پور پرسیدم:

بهت چرا نیست از static method استفاده کنیم و get instance رو انجام بدیم؟

استاد برام یه ویس فرستادن. جواب استاد رمضان پور با یه کوچولو اصلاح این بود: 
«...این اشتباهی یه که تو یکی دیگه از سوالاتی که تو یه تاپیک دیگه مربوط به همین Singleton پرسیده شده بود وجود داره. یعنی هر 2 تا سوال این اشکال رو دارن. من نکته‌ام اینه که وقتی یه کلاسی Singleton میشه، هیچ ابجکت اضافی ای ازش ساخته نشه یعنی کلا در طول اجرای برنامه فقط یکبار، ابجکت از اون کلاس ساخته بشه. ولی سوالی که دوستان دارن میگن که خب چه اشکالی داره ما هر بار که صدا زده میشه یه ابجکت بسازیم ولی اون ابجکت اولی یه که ساختیم رو برگردونیم. یعنی اگر 10 بار صدا زده میشه. ما دفعه اول یه ابجکتی بسازیم یه جایی ذخیره کنیم. بار دوم یه ابجکت جدید بسازیم، اولی یه رو برگردونیم. بار سوم یه ابجکت جدید بسازیم اولی یه رو برگردونیم. خب این که خیلی کار عجیب غربیه که...
توی هر 2 تا سناریو، توی هر 2 تا سوال این اتفاق می‌افته. من توی ویدیو هم گفتم. گفتم رسیدن به init یعنی اینکه اون self ساخته شده و یه فضایی توی حافظه اشغال کرده و آدرسی تو حافظه داره. و گرنه این که خیلی ساده است که ما یه if میذاشتیم توی init و میگفتیم که اگر قبلا ساخته شده اون قبلی یه رو برگردون. ولی نکته این جاست که همین الان هم دوباره یه دونه جدید ساخته میشه و حالا ما فقط نهایتا ناقص ولش میکنیم یعنی مقدار دهیش نمیکنیم. و این اتفاقا یه آنتی پترنه توی Singleton یعنی خیلی نهی شده این کار توی تعاریف Singleton که آقا به هیچ وجه اینکارو نکنید! و یه جوری کلاس تون رو بنویسید که فقط یه نمونه ازش ساخته بشه...»

محمدعلی رضا ۰۷ آذر ۱۳۹۹، ۰۷:۴۳