راه
۵ کیو· متوسط رو به بالامتوسطPYTHON۴ ثانیه · ۲۵۶ مگابایت

کلاس WorkPlace

استثنای WorkPlaceIsFull، کلاس Consts و کلاس WorkPlace را در همین یک فایل بنویس. داور برای آزمودن متدهای خالی (calc_capacity، calc_costs) زیرکلاس‌های کوچکی می‌سازد؛ نیازی به فایل work_place.py نیست.

پس از پیاده‌سازی کلاس بنیادین Person، اکنون نوبت به کلاس دیگری از موجودیت‌های اصلی مدل ما، یعنی کلاس WorkPlace (محل کار)، می‌رسد. این کلاس نقش مدل‌سازی مکان‌هایی را دارد که افراد در آن‌ها مشغول به کار می‌شوند. کلاس WorkPlace ویژگی‌ها و رفتارهای مشترک انواع مختلف محل کار (مانند معدن، مدرسه و شرکت) را تعریف می‌کند و مانند کلاس Person، پایه‌ای برای زیرکلاس‌های خود خواهد بود.

کد کلاس WorkPlace در فایل work_place.py قرار خواهد گرفت.


استثنای سفارشی WorkPlaceIsFull

قبل از شروع به پیاده‌سازی کلاس WorkPlace، یک استثنای سفارشی به نام WorkPlaceIsFull تعریف می‌کنیم. این استثنا برای مدیریت حالتی استفاده می‌شود که سعی در استخدام فرد در یک محل کار با ظرفیت کامل داشته باشیم. این یک کلاس ساده است که از کلاس پایه Exception ارث‌بری می‌کند و صرفاً یک پیام خطا را برمی‌گرداند.

python
class WorkPlaceIsFull(Exception):
    def __str__(self):
        return "work place is full!"

ثابت‌های پروژه: کلاس Consts

در طول پروژه، از مقادیر ثابتی مانند قیمت‌های پایه برای محاسبه‌ی هزینه‌ها استفاده می‌کنیم. برای سازماندهی این مقادیر، یک کلاس ساده به نام Consts تعریف می‌شود که این مقادیر ثابت را در خود نگه می‌دارد. بخشی از این کلاس که مربوط به قیمت‌های پایه ساخت محل کار است، به‌صورت زیر تعریف می‌شود. برخی از این ثابت‌ها را در این قسمت نیاز نداریم و در بخش‌های بعدی استفاده می‌شوند.

python
class Consts:
    BASE_PRICE = {'mine': 150, 'school': 100, 'company': 90}
    BASE_PLACE_COST = 2500
    LEVEL_MUL = 50

کلاس WorkPlace

  • instances: یک متغیر کلاس است که لیستی از تمام اشیاء WorkPlace را که تاکنون ایجاد شده‌اند، نگهداری می‌کند. هر شیء جدید WorkPlace هنگام ساخت به این لیست اضافه می‌شود.
  • name: نام محل کار است و از نوع رشته است.
  • level: سطح فعلی محل کار است. از نوع عدد صحیح است و با مقدار اولیه‌ی ۱ شروع می‌شود.
  • expertise: نوع تخصص محل کار (مانند "mine"، "school" و "company") است. از نوع رشته است و با مقدار اولیه‌ی "" (رشته خالی) شروع می‌شود و در زیرکلاس‌ها مقداردهی می‌شود.
  • employees: لیستی از اشیاء Person که در این محل کار مشغول هستند. با لیست خالی [] شروع می‌شود.
  • capacity: حداکثر تعداد افرادی که می‌توانند در این محل کار مشغول باشند. از نوع عدد صحیح است، با مقدار اولیه‌ی ۱ شروع می‌شود و با ارتقاء سطح به‌روزرسانی می‌شود.

متد سازنده: init(self, name)

  • پارامتر name برای مقداردهی ویژگی name شیء استفاده می‌شود.
  • ویژگی level با مقدار 1، expertise با ""، employees با [] و capacity با 1 مقداردهی اولیه می‌شوند.
  • شیء self به لیست WorkPlace.instances اضافه می‌شود تا ردیابی تمام محل‌های کار امکان‌پذیر باشد.

متد get_price(self)

این متد هزینه‌ی ساخت این محل کار را بر اساس نوع تخصص آن (self.expertise) از دیکشنری BASE_PRICE در کلاس Consts برمی‌گرداند.

متد upgrade(self)

این متد سطح محل کار (self.level) را یک واحد افزایش می‌دهد. پس از افزایش سطح، متد self.calc_capacity() را فراخوانی می‌کند تا ظرفیت محل کار بر اساس سطح جدید محاسبه و به‌روزرسانی شود.

متد hire(self, person)

این متد مسئول استخدام یک فرد (person که یک شیء Person است) در این محل کار است. قبل از استخدام، ظرفیت فعلی محل کار (self.capacity) با تعداد کارمندان فعلی (len(self.employees)) مقایسه می‌شود. اگر محل کار پر باشد (تعداد کارمندان بیشتر یا مساوی ظرفیت)، استثنای WorkPlaceIsFull رخ می‌دهد (raise WorkPlaceIsFull()). در غیر این صورت، شیء person به لیست self.employees اضافه می‌شود و ویژگی work_place شیء person برابر با این محل کار قرار داده می‌شود تا فرد به محل کار متصل شود.

متد calc_capacity(self)

این متد مسئول محاسبه‌ی ظرفیت حداکثر کارمند برای محل کار بر اساس سطح فعلی آن (self.level) است. منطق محاسبه‌ی ظرفیت برای انواع مختلف محل کار متفاوت است (مثلاً معدن ممکن است با مدرسه فرق داشته باشد). بنابراین، پیاده‌سازی واقعی این متد در زیرکلاس‌های Mine، School و Company انجام خواهد شد. در کلاس پایه‌ی WorkPlace، این متد به‌صورت خالی با pass تعریف می‌شود.

متد calc_costs(self)

این متد مسئول محاسبه‌ی هزینه‌های نگهداری روزانه برای این محل کار است. مجدداً منطق محاسبه‌ی هزینه نیز برای انواع مختلف محل کار متفاوت است. مانند calc_capacity، پیاده‌سازی واقعی این متد در زیرکلاس‌ها انجام خواهد شد. در کلاس پایه‌ی WorkPlace، این متد به‌صورت خالی با pass تعریف می‌شود.

متد get_expertise(self)

این متد صرفاً مقدار ویژگی self.expertise را که نشان‌دهنده نوع تخصص محل کار است، برمی‌گرداند.

متد calc(self)

این متد وضعیت مالی خالص روزانه‌ی مربوط به خود محل کار را محاسبه می‌کند. معمولاً محل‌های کار درآمدی تولید نمی‌کنند (این افراد هستند که درآمد تولید می‌کنند)، بلکه صرفاً هزینه دارند. بنابراین، این متد منفیِ هزینه‌ی نگهداری روزانه را که توسط متد self.calc_costs() محاسبه می‌شود، برمی‌گرداند.

متد calc_all()

این متد به عنوان یک متد ایستا (Static Method) تعریف شده‌است و مسئول محاسبه‌ی مجموع وضعیت مالی روزانه‌ی تمام محل‌های کاری است که در مدل ما وجود دارند. برای این کار، این متد روی لیست WorkPlace.instances (که شامل تمام اشیاء WorkPlace است) پیمایش می‌کند و برای هر شیء، متد calc() آن محل کار را فراخوانی کرده و نتایج را با هم جمع می‌بندد. در نهایت، مقدار مجموع نهایی را برمی‌گرداند.

python
def __init__(self, name):
    self.name = name
    self.level = 1
    self.expertise = ""
    self.employees = []
    self.capacity = 1
    WorkPlace.instances.append(self)
python
def get_price(self):
    return Consts.BASE_PRICE[self.expertise]
python
def upgrade(self):
    self.level += 1
    self.calc_capacity()
python
def hire(self, person):
    if len(self.employees) >= self.capacity:
        raise WorkPlaceIsFull()
    self.employees.append(person)
    person.work_place = self
python
def calc_capacity(self):
    pass
python
def calc_costs(self):
    pass
python
def get_expertise(self):
    return self.expertise
python
def calc(self):
    return -self.calc_costs()
python
@staticmethod
def calc_all():
    total = 0
    for wp in WorkPlace.instances:
        total += wp.calc()
    return total

💡 چالش‌های حل تمرین

⚠️ چگونه می‌توانم به ویژگی instances دسترسی داشته باشم؟

ویژگی instances مربوط به کلاس است (نه به شیء)؛ بنابراین به‌صورت WorkPlace.instances می‌توان به این ویژگی دسترسی داشت.

⚠️ در متد hire() از try...except استفاده کردم ولی تابع به‌درستی کار نمی‌کند. مشکل چیست؟

در تابع hire() نیازی به استفاده از try...except نیست. با استفاده از if...else می‌توان خواسته‌ی تمرین را برآورده کرد.

⚠️ چگونه در متد hire() محل کار شخص را برابر این محل کار قرار دهم؟

برای این که محل کار شخص را برابر self قرار دهید، می‌توانید به‌صورت زیر عمل کنید:

python
person.work_place = self

⚠️ مشکلات متداول

  • در هیچ‌کدام از توابع نباید مقداری را چاپ کنید، بلکه باید مقادیر خواسته‌شده را با استفاده از return برگردانید.

✅ این تمرین را در ویرایشگر خود پیاده‌سازی کنید. به یاد داشته باشید که کلاس WorkPlace باید در فایل work_place.py قرار گیرد.

نمونه‌ها

ورودی نمونه ۱
w = WorkPlace("Base")
[w.name, w.level, w.expertise, w.employees, w.capacity]
WorkPlace.instances[-1] is w
خروجی نمونه ۱
['Base', 1, '', [], 1]
True
ورودی نمونه ۲
class Mine(WorkPlace):
    def __init__(self, name):
        super().__init__(name)
        self.expertise = "mine"

m = Mine("M1")
[m.get_price(), m.get_expertise()]
خروجی نمونه ۲
[150, 'mine']
ورودی نمونه ۳
class P:
    work_place = None

w = WorkPlace("W")
x = P()
w.hire(x)
x.work_place is w
try:
    w.hire(P())
except WorkPlaceIsFull as error:
    print(error)
len(w.employees)
خروجی نمونه ۳
True
work place is full!
1
ورودی نمونه ۴
class Grow(WorkPlace):
    def calc_capacity(self):
        self.capacity = self.level * 3

g = Grow("G")
g.upgrade()
[g.level, g.capacity]
خروجی نمونه ۴
[2, 6]
ورودی نمونه ۵
class Costly(WorkPlace):
    def calc_costs(self):
        return 100 * self.level

a = Costly("a")
b = Costly("b")
b.upgrade()
[a.calc(), b.calc(), WorkPlace.calc_all()]
خروجی نمونه ۵
[-100, -200, -300]
ورودی نمونه ۶
[str(WorkPlaceIsFull()), issubclass(WorkPlaceIsFull, Exception)]
خروجی نمونه ۶
['work place is full!', True]

برای نوشتن پاسخ و دریافت امتیاز، ابتدا وارد حساب شوید.

ورود