.لینکهای مفید برای شرکت در مسابقه:
میتوانید سوالهای خود را در رابطه با سوالات و دیگر بخشهای پایتون از قسمت "سوال بپرسید" مطرح کنید.
توجه کنید که نسخه پایتون استفاده در سوالات ۳.۷ است. سری سوم راهنماییها به مرور به سوالات اضافه میشوند.
میخواهیم کمککنندهای (helper
) بنویسیم که در موارد مشخص Exceptionها را لاگ کند و از آن بگذرد.
کریم در حال خواندن سوالات بود که از من به عنوان نویسندهی سوالات بابت توهینهایی که به کریم کردم در نداشتن توانایی یاد گرفتن برنامهنویسی دلخور شد. برای همین سوالی را طرح کرد که به من بفهماند که من هم توانایی یاد گرفتن برنامهنویسی را ندارم. از شما میخواهم به جای من سوال زیر را حل کنید.
سوال از این قرار است که باید در پایتون کمک کنندهای به نام PyRanj
پیادهسازی کنید به صورتی که این کمککننده سه قابلیت اصلی زیر را داشته باشد:
هر گاه از pyranj
به عنوان wrapper یک تابع استفاده شود، در تابع مورد نظر نباید هیچ تغییری ایجاد شود و فقط در زمان صدا زدن تابع، در صورتی که Exception پرتاب شود، صرفا باید این اتفاق لاگ شود و برنامه ادامه پیدا کند. برای مثال در کد زیر باید خروجی پایینی لاگ شود:
هرگاه از pyranj
به عنوان context
استفاده شود، در عملیات مورد نظر نباید هیچ تغییری ایجاد شود و فقط اگر حین انجام عملیات، Exception پرتاب شود، صرفا باید این اتفاق لاگ شود و برنامه ادامه پیدا کند. برای مثال در کد زیر باید خروجی پایینی لاگ شود:
هرگاه از pyranj
در کلاسی ارثبری شود، در صورتی که آن کلاس دارای متد run باشد، تغییری که ایجاد میشود باید برابر با لاگشدن Exception
با فرمت مشخص شده باشد. برای مثال در کد زیر باید خروجی پایینی لاگ شود:
توجه: برای لاگ کردن باید از متد log
شی logger
به شیوهی زیر عمل کنید و به آن یک رشته ورودی دهید (از اینجا میتوانید نمونه logger
که در تستها استفاده میشود را دانلود کنید):
علاوه بر قابلیتهای اصلی، کمککنندهی شما باید دارای قابلیتهای زیر نیز باشد.
prefix
در متن لاگ🔗توجه کنید که این نوع از تغییر prefix در تمام ویژگیهای اصلی باید وجود داشته باشد.
prefix
در متن لاگ🔗توجه: متنی که به ازای هر Exception لاگ میشود باید به فرمت زیر باشد، که در آن مقدار پیشفرض prefix
، برابر است با [EXCEPTION]
.
برای فهمیدن بهتر سوال میتوانید مثال زیر و خروجی آن را مشاهده کنید.
pyranj.py
باشد که در آن شی PyRanj
وجود داشته باشد و ویژگیهای گفته شده را داشته باشد.BasePyRanjTest
TestPyRanjInstantiation
TestPyRanjInstantiationWithPrefix
TestPyRanjRecursiveInstantiation
TestPyRanjRecursiveInstantiationWithPrefix
در این قسمت راهنماییهای سوال به ترتیب در روزهای شنبه، دوشنبه و چهارشنبه ساعت ۱۸ اضافه میشود. مشکلاتتان در راستای حل سوال را میتوانید از بخش "سوال بپرسید" مطرح کنید.
توصیه میشود ابتدا در مورد مفاهیم wrapper, contextManager, Mixin از این لینکها بخوانید:
توجه کنید که helper
مورد نظر لزومی ندارد به صورت عادی تعریف شود و میتواند خودش حاصل فراخوانی یک تابع دیگر باشد.
برای این که helper
مورد نظر به طور همزمان قابل ارثبری باشد و همچنین قابل فراخوانی، میتوان از تابع __call__
در metaclass
کمک گرفت. برای اطلاع ازین مورد میتوانید لینک زیر را بخوانید:
ابتدا یک decorator عادی تعریف کنید که یک prefix ورودی میگیرد و یک تابع را تغییر میدهد.
سپس تابعی تعریف کنید به اسم get_pyranj که یک prefix هم ورودی میگیرد. اینگونه در هرجایی از class یا metaclass به آن prefix دسترسی دارید. درون تابع metaclass و class مربوطه را تعریف کنید و در خروجی آن class مورد نظر را برگردانید.
توابع enter و exit را در metaclass بیفزایید (در تابع exit میتوانید بفهمید آیا در طول اجرا با این کانتکست Exception پرتاب شده است یا نه. حالا برای اینکه حالت ارثبری را به درستی هندل کنید، متود getattribute را در class باز نویسی کنید. و در صورتی که attribute مورد نظر اسمش برابر با run بود آن را دکوریت کنید.
اگر توجه داشته باشید موقع فراخوانی این helper سه حالت ممکن است پیش بیاید (ساخته شدن یک آبجکت جدید که از helper ارث بری کرده است، دکوریت کردن یک تابع، و تحویل گرفتن دکوریتور با یک prefix به عنوان ورودی) که میتوان در متود call_ در metaclass آنها را هندل کرد
کد نهایی سوال به شکل زیر میشود: