پرسشنامه
تمرین ۱ – پرسشهای مفهومی
۱. شیءگرایی در اواخر دههی ۱۹۶۰ متولد شد، در دورانی که کد بهصورت دنبالهای از دستورها روی حافظه اجرا میشد؛ متغیرهای گلوبال همهجا در دسترس بودند و پرشهای GOTO جریان برنامه را درهمتنیده میکردند («کد اسپاگتی»). مشکل اصلی این بود: با بزرگتر شدن برنامهها، هیچکس دیگر نمیتوانست کل برنامه را در ذهنش نگه دارد؛ یک تغییر کوچک در گوشهای، جای دیگری را بهشکل غیرمنتظره خراب میکرد، چون داده آزادانه بین همهی توابع دستبهدست میشد. شیءگرایی برای مهار این پیچیدگی آمد: داده و رفتار مربوط را کنار هم در یک واحد بسته گذاشتن و کنترل دسترسی به داده.
۲.
- Simula (اوله-یوهان دال و کریستن نیگارد): تمرکز بر کلاس، نوع و ساختار داده برای شبیهسازی سیستمهای واقعی.
- Smalltalk (آلن کی): تمرکز بر پیامرسانی میان اشیای مستقل.
در یک جمله: Simula شیء را «نمونهای از یک قالب» میدید، اما Smalltalk شیء را «موجودی مستقل که پیام رد و بدل میکند».
۳. این نگاه، ریشهی مستقیم کپسولسازی (Encapsulation) است. چون در مدل پیامرسانی، شما نمیتوانید دادهی داخلی شیء را مستقیم دستکاری کنید؛ فقط میتوانید به آن پیام بفرستید و خود شیء تصمیم میگیرد در پاسخ چه کند. این یعنی دادهی درونی از دسترس مستقیم بیرون پنهان و محافظت میشود — تعریف کپسولسازی.
۴.
- رویهای (Procedural): اسکریپتهای کوتاه، برنامهنویسی سیستمی.
- شیءگرا (Object-Oriented): سیستمهای بزرگ، فریمورکها، مدلسازی موجودیتها.
- تابعی (Functional): پردازش داده، همروندی و محاسبات موازی.
- منطقی (Logic): استنتاج، سیستمهای خبره و هوش مصنوعی کلاسیک.
۵. یعنی پایتون شما را به یک سبک واحد قفل نمیکند؛ میتوانید در یک پروژه رویهای، شیءگرا و تابعی را با هم به کار ببرید. مزیت: آزادی انتخاب بهترین ابزار برای هر مسئله. مسئولیت: خودتان باید بدانید کی کدام سبک مناسب است — این تصمیم بر عهدهی شماست، نه زبان.
تمرین ۲ – نقدها و فلسفه
۶.
- دشواری مدیریت State: وقتی دهها شیء همزمان حالت هم را تغییر میدهند، فهمیدن «وضعیت کنونی کل سیستم» سخت میشود.
- شکنندگی ارثبری: سلسلهمراتب عمیق ارثبری باعث میشود تغییر در والد، فرزندان را بهشکل غیرمنتظره بشکند.
- کپسولسازی قراردادی در پایتون: پایتون
privateاجباری ندارد؛ فقط قرارداد دارد، پس محافظت واقعی وجود ندارد.
۷. این استعاره دربارهی شکنندگی ارثبری (و وابستگی ضمنی کلاسها) است. منظور: وقتی از یک کلاس ارث میبرید، فقط آن یک قابلیتی را که میخواستید نمیگیرید؛ کل زنجیرهی وابستگیها و محیط ضمنی والدها هم با آن میآید. «موز» را خواستی، اما «گوریل و کل جنگل» را هم گرفتی.
۸. یعنی «اینجا همهی ما بزرگسالیم». پایتون بهجای اینکه با قفل و اجبار جلوی دسترسی به دادهی داخلی را بگیرد، به قرارداد و مسئولیتپذیری برنامهنویس تکیه میکند. این به ویژگی کپسولسازی قراردادی مربوط است (استفاده از _ و __ بهجای private اجباری).
تمرین ۳ – تاریخچهی پایتون و MRO
۹. در نسخهی ۲.۲ (سال ۲۰۰۱). مهمترین تغییر این بود که شکاف میان کلاسهای کاربر و نوعهای توکار پایتون از بین رفت: هر کلاس بهطور ضمنی از object ارث میبرد (یعنی «همهچیز یک شیء است»)، میشد از نوعهای توکار مثل list ارث برد، الگوریتم MRO به C3 تغییر کرد و super() درست کار میکرد.
۱۰. در پایتون ۳ هیچ تفاوتی ندارند؛ کاملاً معادلاند. همهی کلاسها بهطور خودکار از object ارث میبرند، پس نوشتن یا ننوشتن (object) فرقی نمیکند. (این تمایز فقط در پایتون ۲ معنا داشت.)
class User:
pass
print(User.__bases__) # (<class 'object'>,)
۱۱. MRO یا Method Resolution Order، ترتیبی است که پایتون برای جستوجوی یک متد دنبال میکند (بهویژه وقتی کلاس از چند والد ارث برده). پایتون امروز از الگوریتم C3 Linearization استفاده میکند که تضمین میکند: هر کلاس پیش از والدهایش بررسی شود، ترتیب نوشتن والدها حفظ شود، و ترتیبی یکتا برای کل سلسلهمراتب وجود داشته باشد.
۱۲. خروجی:
B
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
چرا؟ طبق MRO، جستوجو از D شروع میشود؛ چون D خودش hello ندارد، به B میرود (نفر بعدی در MRO) و آنجا hello را پیدا میکند و "B" را برمیگرداند — پیش از آنکه به C یا A برسد. ترتیب کامل جستوجو D → B → C → A → object است.
تمرین ۴ – مقایسه و تحلیل
۱۳.
| ویژگی | Python | Java |
|---|---|---|
| ارثبری چندگانه | ✅ دارد | ❌ ندارد (فقط Interface) |
| کپسولسازی | قراردادی (_, __) | اجباری (private) |
| نوعبندی | پویا (+ Type Hints) | ایستا |
۱۴. دلایل (دستکم دو مورد):
- هر دو پویا (Dynamic) هستند؛ نوع در زمان اجرا مشخص میشود.
- هر دو ارثبری چندگانه (یا معادلش) را پشتیبانی میکنند.
- هر دو قراردادمحوراند نه اجبارمحور؛ به بلوغ برنامهنویس تکیه میکنند بهجای قفل اجباری.
۱۵. پیشنیازها (سه مورد یا بیشتر): متغیرها و انواع داده؛ ساختارهای دادهی پایه (لیست، دیکشنری، تاپل، مجموعه)؛ شرطها (if/elif/else)؛ حلقهها (for/while)؛ و توابع (تعریف، پارامتر، مقدار بازگشتی). نکته: تسلط بر تابع مهمترین است، چون متد چیزی جز تابع چسبیده به شیء نیست.
۱۶. سه دلیل (از میان موارد فصل):
- فریمورکها: جنگو، FastAPI، Flask و SQLAlchemy همه بر پایهی OOPاند.
- الگوهای طراحی: Factory، Strategy، Observer و… به زبان کلاس و شیء بیان میشوند.
- معماری و تست: Clean Architecture، تستنویسی حرفهای (Mock، Fixture) و آگهیهای استخدام همه به OOP نیاز/اشاره دارند.
تمرین ۵ – پرسش تحلیلی
۱۷. این جمله نادرست است، چون بر یک تفکر «همه یا هیچ» استوار است که با مفهوم Tradeoff در تضاد است. وجود نقد بر یک پارادایم به این معنا نیست که باید کاملاً کنارش گذاشت. هر پارادایم برای دستهای از مسائل مناسبتر است: تابعی برای پردازش داده و همروندی عالی است اما در مدلسازی موجودیتهای پرحالت دنیای واقعی ضعیف است؛ شیءگرایی دقیقاً برعکس. پاسخ درست این نیست که «همیشه X» بلکه این است که «بسته به مسئله، گزینهها را بسنج و مناسبترین را انتخاب کن». حتی خود پایتون چندپارادایمی است تا اجازه دهد در یک پروژه از هر دو بهره ببرید. نقدها ارزشمندند چون به ما یاد میدهند شیءگرایی را هوشمندانه به کار ببریم، نه اینکه کورکورانه ردش کنیم.