سطح مقدماتی (Beginner Level)
دروننگری یا Introspection به توانایی یک برنامه برای بررسی نوع (Type) و ویژگیهای یک شیء (Object) در زمان اجرا گفته میشود. پایتون به عنوان یک زبان پویا (Dynamic)، ابزارهای بسیار قدرتمندی را برای این کار در اختیار شما قرار میدهد.
۱. بررسی نوع داده (type و isinstance)
سادهترین شکل دروننگری، فهمیدن نوع یک متغیر است.
type(obj): نوع دقیق کلاس شیء را برمیگرداند.isinstance(obj, class): بررسی میکند آیا شیء نمونهای از آن کلاس (یا کلاسهای فرزند آن) هست یا خیر.
مثال ۱: تفاوت type و isinstance
در این مثال میبینیم که isinstance وراثت را در نظر میگیرد اما type فقط کلاس دقیق را چک میکند.
مثال ۲: بررسی انواع دادههای ساده
۲. بررسی محتویات شیء (dir و vars)
برای اینکه بفهمیم یک شیء چه متدها و ویژگیهایی (Attributes) دارد، از dir() استفاده میکنیم.
dir(obj): لیستی از نامهای تمام متدها و ویژگیهای قابل دسترس شیء را برمیگرداند.vars(obj): دیکشنری__dict__شیء را برمیگرداند (فقط ویژگیهای قابل تغییر و اختصاصی).
مثال ۱: استفاده از dir روی لیست مشاهده تمام متدهایی که یک لیست دارد (مثل append, pop و ...).
مثال ۲: استفاده از vars روی کلاس سفارشی
سطح پیشرفته (Professional Level)
در سطح حرفهای، دروننگری فقط برای "دیدن" نیست، بلکه برای برنامهنویسی پویا (Metaprogramming) و ساخت سیستمهای انعطافپذیر (مانند ORMها یا Plugin Systemها) استفاده میشود.
۱. دسترسی پویا به ویژگیها (getattr, setattr, hasattr)
گاهی اوقات نام متد یا متغیری که میخواهید صدا بزنید، در یک رشته (String) ذخیره شده است.
hasattr(obj, 'name'): آیا این ویژگی وجود دارد؟getattr(obj, 'name', default): مقدار ویژگی را میگیرد.setattr(obj, 'name', value): مقدار ویژگی را تغییر میدهد یا میسازد.delattr(obj, 'name'): ویژگی را حذف میکند.
مثال ۱: فراخوانی متد با نام رشتهای فرض کنید نام متد را از کاربر میگیرید یا در دیتابیس ذخیره کردهاید.
مثال ۲: مقداردهی پویا (Dynamic Assignment) پر کردن ویژگیهای یک کلاس بر اساس یک دیکشنری (مشابه کاری که کتابخانههای JSON انجام میدهند).
۲. بررسی قابل فراخوانی بودن (callable)
قبل از اینکه پرانتز () را جلوی یک نام بگذارید، باید مطمئن شوید که آن شیء یک تابع یا کلاس است.
مثال ۱: جلوگیری از خطا هنگام اجرا
۳. ماژول inspect (کالبدشکافی کد)
ماژول inspect ابزارهای بسیار پیشرفتهتری نسبت به توابع داخلی ارائه میدهد. شما میتوانید سورس کد یک تابع را بگیرید، آرگومانهای آن را بررسی کنید یا پشته فراخوانی (Stack Trace) را ببینید.
مثال ۱: دیدن پارامترهای یک تابع این تکنیک در ساخت فریمورکهای وب (مثل FastAPI یا Django) برای تزریق وابستگی (Dependency Injection) بسیار کاربرد دارد.
مثال ۲: دریافت سورس کد تابع شما حتی میتوانید کد نوشته شده درون یک تابع را به صورت رشته دریافت کنید.
نکات فنی و بهترین روشها
- پرهیز از پیچیدگی: استفاده بیش از حد از
getattrوsetattrخوانایی کد را کم میکند. فقط زمانی استفاده کنید که واقعاً نیاز به پویایی دارید. - امنیت: هرگز
getattrرا مستقیماً با ورودیهای تایید نشده کاربر استفاده نکنید، زیرا ممکن است به متدهای داخلی (__init__و ...) دسترسی پیدا کنند. - کارایی: توابع دروننگری (Reflection) کمی کندتر از دسترسی مستقیم به ویژگیها هستند، بنابراین در حلقههای بسیار سنگین (High Performance Loops) با احتیاط استفاده شوند.
# Static snippet: الگوی رایج در پلاگیننویسی
def load_plugin(plugin_name):
module = __import__(plugin_name)
if hasattr(module, 'setup'):
module.setup()