چیراکسی؟
برای متمرکز کردن مدیریت و نمایندگی اطلاعات مربوط به استثناها در یک ساختار یکپارچه، در این تمرین از یک کلاس به نام ExceptionProxy استفاده میکنیم. هدف این است که بهازای هر فراخوانی تابع، چه موفقیتآمیز باشد چه منجر به استثنا شود، یک شیء از این کلاس ایجاد کنیم که وضعیت آن فراخوانی را در خود نگه دارد.
کلاس
ExceptionProxyنمایندهای (proxy) برای اطلاعات مربوط به یک استثنا یا نتیجهی موفقیتآمیز یک فراخوانی تابع است. هر شیء از این کلاس دو ویژگی اصلی خواهد داشت:
message: متنی شامل پیام استثنا در صورت بروز خطا، یا پیامی مشخص (مانند'ok!') در صورت اجرای موفقیتآمیز.function: شیء تابع پایتونی که فراخوانی شده و منجر به این نتیجه (خطا یا موفقیت) شدهاست.
class ExceptionProxy:
def __init__(self, message, function):
self.message = message
self.function = function
از شما میخواهیم تابعی به نام
transform_exceptionsبنویسید که:
- یک لیست از توابع را بهعنوان ورودی میگیرد. فرض کنید تمام توابع در این لیست بدون آرگومان هستند.
- به ترتیب، هر تابع موجود در لیست ورودی را فراخوانی میکند.
- برای هر فراخوانی تابع، یک شیء جدید از کلاس
ExceptionProxyایجاد میکند.- اگر فراخوانی تابع با موفقیت انجام شد، شیء
ExceptionProxyایجادشده را باmessageبرابر با رشته'ok!'وfunctionبرابر با همان تابعِ فراخوانیشده، مقداردهی میکند.- اگر در حین فراخوانی تابع استثنایی رخ داد، شیء
ExceptionProxyایجادشده را باmessageبرابر با پیام متنی استثنای رخداده وfunctionبرابر با همان تابعِ فراخوانیشده، مقداردهی میکند.- در نهایت، تابع
transform_exceptionsباید یک لیست شامل تمام اشیاءExceptionProxyایجادشده (به همان ترتیب توابع ورودی) را بازگرداند.
🎯 نمونه
def f():
return 1 / 0
def g():
pass
exceptions_info = transform_exceptions([f, g])
for item in exceptions_info:
print(f"function: {item.function}")
print(f"function name: {item.function.__name__}")
print(f"message: {item.message}")
print("-" * 10)
خروجی:
function: <function f at 0x...>
function name: f
message: division by zero
----------
function: <function g at 0x...>
function name: g
message: ok!
----------
همانطور که در خروجی مشاهده میشود، اجرای تابع
fمنجر به استثنایZeroDivisionErrorبا پیامdivision by zeroشده است که در شیءExceptionProxyمربوط به آن ذخیره شدهاست. از سوی دیگر، اجرای تابعgموفقیتآمیز بوده و پیامok!برای آن ثبت شدهاست. در هر دو حالت، شیء تابع اصلی نیز در ویژگیfunctionنگهداری شدهاست.
💡 چالشهای حل تمرین
⚠️ کلاس
ExceptionProxyرا چگونه پیادهسازی کنم؟کلاس
ExceptionProxyتنها دارای یک تابع سازنده است که دو مقدارmessageوfunctionرا گرفته وself.messageوself.functionرا با این مقادیر مقداردهی میکند.
⚠️ چگونه توابعی که داخل لیست
func_lsقرار دارند را صدا بزنم؟برای صدا زدن هر تابع از لیست
func_lsباید با استفاده ازforیک پیمایش روی اعضای این لیست انجام دهید. اگر هر عضو از این لیستfuncنام گیرد، بهصورتfunc()میتوان آن را فراخوانی کرد:
for func in func_ls:
...
func()
...
⚠️ چگونه میتوانم به متن پیام یک استثنا دسترسی داشته باشم؟
بهصورت زیر میتوانید به پیام یک استثنا دسترسی پیدا کنید (متغیر
messageحاوی متن خطا خواهد بود).
try:
...
except Exception as e:
...
message = str(e)
⚠️ چگونه تابع را در ویژگی
functionقرار دهم؟نیازی نیست نام تابع را در ویژگی
functionقرار دهید؛ بلکه باید خود تابع در آن قرار گیرد. اگر هنگام پیمایش رویfunc_lsنامfuncرا روی هر تابع گذاشته باشید، باید همین تابعfuncرا مستقیماً در ویژگیfunctionشیئی که از کلاسExceptionProxyساختهاید، قرار دهید.💡 نکته: استفاده از
__name__در مثال تنها جهت نمایش خروجی نمونه است که خارج از تابعtransform_exceptionsقرار گرفتهاست و در داخل کلاسExceptionProxyیا تابعtransform_exceptionsنباید نام تابع را به جای خود شیء تابع ذخیره کنید.
⚠️ خروجی تابع
transform_exceptionsچیست؟تابع
transform_exceptionsنباید چیزی را چاپ کند، بلکه باید لیست اشیاءExceptionProxyرا با استفاده ازreturnبازگرداند.
💡 راهنمایی نهایی
ساختار کلی تابع transform_exceptions به این شکل است:
def transform_exceptions(func_ls):
result = []
for func in func_ls:
try:
func()
proxy = ExceptionProxy("ok!", func)
except Exception as e:
proxy = ExceptionProxy(str(e), func)
result.append(proxy)
return result
- یک لیست خالی به نام
resultبرای ذخیرهی اشیاءExceptionProxyایجاد میکنیم.- با یک حلقه
forروی توابع ورودی پیمایش میکنیم.- در بلوک
try، تابع را فراخوانی میکنیم و اگر موفق بود، یک شیءExceptionProxyبا پیام'ok!'و خود تابع ایجاد میکنیم.- اگر استثنا رخ داد، در بلوک
exceptیک شیءExceptionProxyبا پیام استثنا و خود تابع ایجاد میکنیم.- هر شیء ایجادشده را به لیست
resultاضافه میکنیم.- در نهایت، لیست
resultرا باreturnبرمیگردانیم.
✅ این تمرین را در ویرایشگر خود پیادهسازی کنید. به یاد داشته باشید که تابع
transform_exceptionsباید یک لیست از اشیاءExceptionProxyبرگرداند و چیزی را چاپ نکند.
نمونهها
def f():
return 1 / 0
def g():
pass
result = transform_exceptions([f, g])
[(item.function.__name__, item.message) for item in result][('f', 'division by zero'), ('g', 'ok!')]def a():
raise ValueError("bad value")
def b():
return [][3]
def c():
return {}["k"]
[item.message for item in transform_exceptions([a, b, c])]['bad value', 'list index out of range', "'k'"]
transform_exceptions([])
[]
def h():
return 5
result = transform_exceptions([h])
[result[0].function is h, result[0].message, type(result[0]).__name__][True, 'ok!', 'ExceptionProxy']
def parse():
return int("x")
def fine():
return "ignored"
[item.message for item in transform_exceptions([fine, parse, fine])]['ok!', "invalid literal for int() with base 10: 'x'", 'ok!']
برای نوشتن پاسخ و دریافت امتیاز، ابتدا وارد حساب شوید.
ورود