یه چالش باحال پایتون

سلام؛ چند وقت پیش با یه چالش در وب سایت codewars در زمینه برنامه نویسی پایتون مواجه شدم که نظرم رو جلب کرد و تصمیم گرفتم توی ویرگول با شما هم درمیون بزارم.شرح چالشتابعی بنویسید که اینطور عمل کنهadd(1)(2) #result: 3 add(4)(4) #result: 8 add(5)(5)(5) #result: 15مطمئنم حدس زدید که عملکردش چیه. ما این تابع رو باید طوری پیاده سازی کنیم که هر چندبار که خواستیم بتونیم فراخوانیش کنیم و هر بار یک عدد جدید به عنوان آرگومان بهش بدیم. در نهایت این تابع باید جمع تمام اعدادی که بهش به عنوان آرگومان داده شده رو بهمون بده.خوب بزارید جمع بندی کنیم:مقدار برگشتی تابع باید یک تابع دیگه باشهمقدار برگشتی تابع باید یک عدد باشهخوب، این بزرگ ترین چالشی هستش که ما در این مسئله داریم. چطور ممکنه یه تابع، هم یک عدد رو به عنوان مقدار برگشتی برگردونه و هم یک تابع دیگه رو؟نکاتی که قبل از حل چالش باید بدونیددر پایتون همه انواع داده، خودشون از نوع object هستند. یعنی اینکه شما می تونید از انواع داده در پایتون مثل str و int و dict و ... ارث بری کنید. اگه این قابلیت نبود خیلی این چالش سخت میشد.آشنایی با متد __call__در پایتون توابع مخصوصی وجود دارند که برای کار های خاصی در نظر گرفته شده اند. اگه با شیء گرایی در پایتون آشنا باشید؛ باید با برخی از این توابع رو بشناسید. مثل __init__ که برای سربار گذاری اولیه (initialization) استفاده میشه (اولین متد مخصوصی که باهاش آشنا میشید معمولا همینه).از متد __call__ برای این استفاده میشه که instance های یک class قابل فراخوانی (callable) بشوند. برای اینکه مطلب جا بیفته به کد زیر توجه کنید.class A: def __init__(self): print (&quotinitialized&quot) def __call__(self): print (&quotthe instance is invoked&quot) instance = A() # initializing the class instance() # calling the instance of type `A` #result: # initialized # the instance is invokedخوب همونطور که میبینید، در کد بالا instance رو دقیقا مثل یک تابع صدا زدیم. این به لطف متد __call__ امکان پذیره. اگر یک object، متد __call__ رو داشته باشه، می تونیم فراخوانیش کنیم اما اگر نداشته باشه، موقع فراخوانی اروری مبنی بر اینکه این شیء قابل فراخوانی نیست خواهیم گرفت.وراثت در پایتونما در پایتون می تونیم ویژگی هایی که کلاس های دیگه دارند رو به ارث ببریم.اگر کلاسی از کلاس دیگر ارث ببره، تمام متد ها و property های اون کلاس رو هم به ارث میبره .در پایین یه مثال ساده رو برای نشون دادن این مطلب آورده امclass A: def hello(self): return &quotHello &quot class B(A): # B inherits from A, so it has a method called hello as well def greet(self, name): return self.hello() + name obj = B() obj.greet(&quotAshkan&quot) # result: 'Hello Ashkan'ما در این کد، دو کلاس به نام A و B داریم، که B از A ارث بری کرده. پس تمام توابع کلاس A در کلاس B هم وجود دارند. اگر به کد های نوشته شده در تابع greet نگاهی بندازید، می فهمید که در اون از تابع hello استفاده شده. تابع hello از کلاس A به B به ارث رسیده.حل چالشخوب تا به اینجا تموم چیز های مورد نیاز رو یاد گرفتید. کاری که قراره انجام بدیم اینه:از روی نوع داده int ارث بری می کنیم و نوع داده جدیدی به نام CustomNumber می سازیم. با این ارث بری که انجام دادیم، دیگه لازم نیست اصلا بدونیم که int چطور کار میکنه. ما تغییرات خودمون رو طوری اعمال می کنیم که رفتار فعلی int رو تغییر نده و در عین حال ویژگی هایی که ما می خواهیم رو اضافه کنه.یک متد __call__ براش تعریف میکنیم که آرگومانی به نام number_to_add داره. number_to_add در اصل همون عددی هستش که قراره با عدد قبلیش جمع بشه. عدد قبلیش چیه؟ خوب همون self میشه.همین دیگه. توضیحات بسه بریم سراغ کد ...class CustomNumber(int): #inherits from int data type def __call__(self, number_to_add): return CustomNumber(self + number_to_add) فقط اینکه یه نکته ای در این کد وجود داره. مقدار برگشتی متد __call__، یک instance از نوع CustomNumber است. دلیل این کارم اینه که self (برخلاف چیزی که انتظار میره) از نوع int هستش. برای همین هربار یک instance جدید از روی CustomNumber میسازیم و به عنوان مقدار برگشتی، برمیگردونیم.البته؛ خوب واقعا دلیلش رو نمیدونم که چرا تو این مورد self از نوع int هستش. اگه شما می دونید؛ خوشحال میشم که در کامنت هاتون بهم بگید.نحوه استفادهadd = CustomNumber(10) # initialize `self` with the value of 10 value = add(20)(50)(30) print (value) # 110