۵ muhammad reza dannak
سوال در مورد id
جامعه پایتون (وب) ایجاد شده در ۱۷ شهریور ۱۴۰۲

سلام و وقت بخیر

class BaseClass(ABC):
    id = 0
    object_list = []
    def __init__(self, *args, **kwargs):
        self.id = self.generate_id()
        self.store(self)
        super().__init__(*args, **kwargs)
    @classmethod
    def generate_id(cls):
        cls.id += 1
        return cls.id
    @classmethod
    def store(cls, obj):
        cls.object_list.append(obj)

این کد مربوط به BaseClass هست. سوالی ذهنم و درگیر کرده که متوجه اش نمیشم. ممنون میشم راهنمایی کنید.

چرا وقتی که id ما مثلا توسط یکی از از فرزندها مثل user به مقدار 5 رسیده، بعد از اینکه ما یک فرزند دیگه مثل House رو میخوایم بسازیم، id به صفر تبدیل میشه و house هم برای خودش id یکتا پیدا میکنه، هرطور فکر میکنم اینا باید پشت سر هم باشن و id ما که قبلا 5 بوده الان 6 باشه اما اینجوری نیست، این در حالیه که house و user همه در object_list ذخیره میشن اما هر کلاسی برای خودش id یکتا میسازه

من بیشتر مشکل مفهومی هست، درک نمیکنم که چرا به این صورت در میاد

اگه بشه به صورت شماتیک بهم یاد بدید ممنون میشم

درود وقتتون بخیر

( به نظرم نباید این اتفاق بیوفته ممنون میشم کل سورس کد رو اپلود کنی تا بیشتر بررسی بشه )

مشکل اصلی در کد این هست که متغیر `id` و `object_list` را به عنوان متغیرهای کلاسی (class variables) در کلاس `BaseClass` تعریف شده. به عبارت دیگه، این متغیرها به اشتراک گذاشته میشن توسط تمامی نمونه‌های این کلاس و زیرکلاس‌های آن. این باعث میشه که وقتی یک زیرکلاس از `BaseClass` مثل `User` یا `House` ایجاد می‌شود، تمام نمونه‌های این کلاس‌ها به یک `id` مشترک دسترسی داشته باشند.

برای رفع این مشکل و ایجاد `id` یکتا برای هر نمونه از کلاس `BaseClass` و زیرکلاس‌های آن، بهتر هستش که از متغیرهای نمونه‌ای (instance variables) برای `id` استفاده کنید. این کار به صورت زیر انجام میشه:

from abc import ABC, abstractmethod
class BaseClass(ABC):
  object_list = []
  def __init__(self, *args, **kwargs):
    self.id = self.generate_id()
    self.store(self)
    super().__init__(*args, **kwargs)
  @classmethod
  def generate_id(cls):
    if not hasattr(cls, 'id'):
      cls.id = 0
    cls.id += 1
    return cls.id
  @classmethod
  def store(cls, obj):
    cls.object_list.append(obj)

با این تغییر، هر نمونه از کلاس `BaseClass` و زیرکلاس‌هاش دارای یک `id` مخصوص خود خواهند بود و تداخلی در اختصاص `id` ندارند.

موفق باشید?

Reza Mobaraki ۱۷ شهریور ۱۴۰۲، ۱۲:۰۰

همون کد اولی که استاد نوشتن و من هم ارسالش کردم، ID مشترک ایجاد نمیکنه، و این تغییری که شما دادید ابتکار خیلی قشنگ و جالبی بود، اما بازهم تمام Object هایی که زیر کلاس BaseClass هستند داخل object_list ریخته میشن و از هر زیر کلاسی میشه به تمامی آبجکت‌ها دسترسی داشت، اساسا آیا این اتفاقی که رخ میده درسته ؟؟؟

ولی سوال اساسی که ذهن من رو درگیر خودش کرده همین هست که وقتی ما generate_id رو کال میکنیم، برای اولین بار id = 1 میشه و این attribute در BaseClass ذخیره میشه یا در زیر کلاس اون مثل User ؟؟؟ اگر در خود BaseClass ذخیر بشه، مثلا ما 5 آبجکت User پشت سر هم بسازیم و بعد یک آبچکت House ایجاد کنیم، حالا آبجکت House باید id ای که میگیره مقدارش 6 باشه، اما id اش یکتاست !!! من درک نمیکنم این بخش رو ...

زمانی که id ایجاد شد و در BaseClass ذخیره شد، پس چرا دوباره صفر میشه وقتی که از یک زیر کلاس جدید میخوایم آبجکت ایجاد کنیم ؟؟؟ این id در BaseClass ذخیره میشه یا در زیر کلاس ؟؟؟

muhammad reza dannak ۱۷ شهریور ۱۴۰۲، ۱۲:۵۲

درود

سوال ۱. خیر این درست نیست در اصل اصول شی گرایی و SOLID رعایت نشده که این اتفاق داره میوفته

سوال ۲ . اگ به کل بحث MRO دقت کنید وقتی شما ارث بری میکنید اون وقت میشه USER ولی چون BaseClass رو داریم به عنوان یک کلاس در هر دو جهت میشه به ویژگی‌های کلاس‌ها دسترسی داشت ( برای اون بخشی ک درک نمیشه مفهومش لطفا سورس کد رو بزارید تا بررسی کنم)

سوال ۳ . موردی که من اینجا بهش رسیدم اینه که شما وقتی داری یک class اتریبیوت مسازی دیگه نباید با self اون رو call کنی اینجا داره همین اتفاق میوفته و اون تبدیل میشه به instance attribute

self.id = self.generate_id()
Reza Mobaraki ۱۷ شهریور ۱۴۰۲، ۱۳:۱۵

ممنون از پاسخ هاتون.

پاسخ سوال اولی، عالی بود، الان متوجه شدم که نباید همه ی آبجکت‌ها رو یک جا ریخت

برای سوال‌های بعدی و اینکه درکم از این داستان درست بشه، سورس کد پیوست میکنم همینجا (اگر بتونید در قالب ویس یا فیلم توضیح بدید که این موضوع بهتر درک بشه ممنون میشم)

muhammad reza dannak ۱۷ شهریور ۱۴۰۲، ۱۳:۳۹

برای سوال اول باید در نظر بگیرید که

توی پروژه‌های اصلی که در ادامه بهشون میرسید خواهید دید که مدل‌های ( مثل کلاس هایی که اینجا نوشتید ) داده هارو توی دیتابیس ذخیره میکنن یا میخونن ، هیچ کجا این امکان نیست که همه داده‌های یک کلاس یا چند کلاس یکجا ذخیره بشه توی یک table از دیتابیس.

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

MR_Rezoo ایدی تلگرام

موفق باشید ?

بهترین پاسخ
Reza Mobaraki ۱۷ شهریور ۱۴۰۲، ۱۵:۰۱