۲. کلاس Shop: ساختن، ذخیره و بارگذاری¶
خط ۸ تا ۲۶
کلاس Shop مغز برنامه است و هیچ ربطی به ظاهر پنجره ندارد. دو داده نگه میدارد: دیکشنری کالاها و لیست فروشها. در این بخش سه متد اول را میبینیم: سازنده که شیء را آماده میکند، save که همهچیز را در فایل مینویسد و load که آن را برمیگرداند.
کد این بخش¶
8class Shop:9 def __init__(self):10 self.products = {}11 self.sales = []12 self.load()13 14 def save(self):15 with open(FILE, 'w', encoding='utf-8') as f:16 json.dump({'products': self.products, 'sales': self.sales}, f, ensure_ascii=False, indent=2)17 18 def load(self):19 if os.path.exists(FILE):20 try:21 with open(FILE, 'r', encoding='utf-8') as f:22 data = json.load(f)23 self.products = data.get('products', {})24 self.sales = data.get('sales', [])25 except (OSError, json.JSONDecodeError, AttributeError):26 self.products, self.sales = {}, []
روی شمارهی هر خط بزن تا به توضیحش بروی؛ روی «خط …» در توضیح بزن تا همان خط در کد روشن شود.
توضیح خط به خط¶
- خط ۸
class Shop:¶ - تعریف کلاس
Shop. کلاس قالبی است که دادهها و رفتارهای مربوط به هم را کنار هم نگه میدارد. این خط هنوز چیزی نمیسازد؛ شیء واقعی در خط ۶۵ باShop()ساخته میشود. - خط ۹
def __init__(self):¶ - متد سازنده. پایتون هر بار که
Shop()صدا زده شود این متد را خودکار اجرا میکند.selfخودِ شیئی است که در حال ساخته شدن است و با آن ویژگیها را روی شیء میگذاریم. - خط ۱۰
self.products = {}¶ - دیکشنری خالی کالاها. کلید هر عضو نام کالاست و مقدارش یک دیکشنری کوچک مثل
{'buy': 1000, 'sell': 1500, 'qty': 3}(قیمت خرید، قیمت فروش، موجودی). - خط ۱۱
self.sales = []¶ - لیست خالی فروشها. هر فروش یک دیکشنری مثل
{'name': 'مداد', 'qty': 2, 'total': 3000}است که در خط ۵۹ اضافه میشود. - خط ۱۲
self.load()¶ - بلافاصله دادههای ذخیرهشده را از فایل میخواند. ترتیب مهم است: اول مقدار پیشفرض خالی ساخته شده (خط ۱۰ و خط ۱۱)، پس اگر فایلی نباشد، شیء با همان مقدارهای خالی کار میکند.
- خط ۱۴
def save(self):¶ - متد
saveهمهی دادهی شیء را در فایل مینویسد. ورودیای جزselfندارد چون همهچیز را از خود شیء برمیدارد. - خط ۱۵
with open(FILE, 'w', encoding='utf-8') as f:¶ - فایل را در حالت نوشتن (
'w') باز میکند. حالت'w'اگر فایل باشد محتوایش را پاک میکند و از نو مینویسد، اگر نباشد میسازد.withتضمین میکند فایل در پایان بسته شود، حتی اگر وسط کار خطا رخ دهد.encoding='utf-8'برای درست ذخیره شدن حروف فارسی لازم است.fنام متغیر فایل باز است. - خط ۱۶
json.dump({'products': self.products, 'sales': self.sales}, f, ensure_ascii=False, indent=2)¶ - یک دیکشنری با دو کلید
productsوsalesمیسازد و باjson.dumpدر فایلfمینویسد.ensure_ascii=Falseباعث میشود فارسی همانطور خوانا ذخیره شود و به شکل\u0645\u062fدر نیاید.indent=2هر سطح را دو فاصله تو میبرد تا فایل برای آدم هم خوانا باشد. - خط ۱۸
def load(self):¶ - متد
loadدادهها را از فایل میخواند و روی شیء میگذارد. فقط از سازنده (خط ۱۲) صدا زده میشود. - خط ۱۹
if os.path.exists(FILE):¶ - اول بررسی میکند فایل وجود دارد. بار اولی که برنامه اجرا میشود فایلی نیست و کل این بلوک رد میشود.
- خط ۲۰
try:¶ - شروع بلوک
try. هر خطایی که در خطوط زیرش رخ دهد، بهجای بستن برنامه به بخشexcept(خط ۲۵) میرود. - خط ۲۱
with open(FILE, 'r', encoding='utf-8') as f:¶ - فایل را در حالت خواندن (
'r') و با همان کدگذاری utf-8 باز میکند. - خط ۲۲
data = json.load(f)¶ json.loadمتن فایل را میخواند و به ساختار پایتون (اینجا یک دیکشنری) تبدیل میکند و درdataمیگذارد.- خط ۲۳
self.products = data.get('products', {})¶ - مقدار کلید
productsرا برمیدارد.getاگر کلید نباشد بهجای خطایKeyErrorمقدار دوم، یعنی{}، را برمیگرداند. - خط ۲۵
except (OSError, json.JSONDecodeError, AttributeError):¶ - سه نوع خطا را میگیرد:
OSErrorوقتی فایل باز نشود (مثلاً دسترسی نباشد)،json.JSONDecodeErrorوقتی محتوای فایل JSON معتبر نباشد، وAttributeErrorوقتی فایل JSON معتبر باشد ولی دیکشنری نباشد (مثلاً یک لیست)، چون لیست متدgetندارد. پرانتز یعنی «هر کدام از اینها».
ارتباط با بقیهی کد¶
همچنین ببینید
Shop- در خط ۶۵ یک نمونه از آن با نام
shopساخته میشود و همهی توابع رابط کاربری از همان استفاده میکنند. self.products- در
addخط ۳۳،editخط ۴۱،deleteخط ۴۷،sellخط ۵۵ و در جدول خط ۱۱۶ خوانده یا تغییر داده میشود. self.sales- در
sellخط ۵۹ عضو جدید میگیرد و درreportخط ۶۳ جمع زده میشود. save()- بعد از هر تغییر صدا زده میشود: خط ۳۴، خط ۴۲، خط ۴۸ و خط ۶۰. خطای فایلش (
OSError) در خط ۹۰ گرفته میشود. load()- فقط یک بار، در سازنده خط ۱۲.
سؤالهای تمرینی¶
اول خودت جواب بده، بعد جواب را باز کن.
بار اولی که برنامه اجرا میشود و فایل داده وجود ندارد چه اتفاقی میافتد؟
withدر خط ۱۵ چه چیزی میدهد کهf = open(...)ساده نمیدهد؟نمایش جواب
فایل در پایان بلوک خودکار بسته میشود، حتی اگر
json.dumpخطا بدهد.فرق
data.get('products', {})باdata['products']چیست؟نمایش جواب
اگر کلید نباشد،
getمقدار{}را برمیگرداند ولیdata['products']خطایKeyErrorمیدهد.محتوای فایل داده
[1, 2]است. وقتی برنامه باز میشود چه میشود؟