ماژول inspect یکی از قدرتمندترین ابزارهای پایتون برای دروننگری (Introspection) است. دروننگری به این معناست که برنامه میتواند در زمان اجرا (Runtime) اطلاعاتی درباره اشیاء موجود در حافظه (مانند توابع، کلاسها، ماژولها و فریمهای پشته) کسب کند. این قابلیت برای ساخت فریمورکها، ابزارهای دیباگ و تولید مستندات خودکار حیاتی است.
سطح مقدماتی (Beginner Level)
در سطح مقدماتی، یاد میگیریم چگونه نوع اشیاء را بررسی کنیم، به سورس کد آنها دسترسی پیدا کنیم و سلسله مراتب کلاسها را مشاهده کنیم.
۱. بررسی نوع اشیاء (Type Checking)
پایتون توابع متعددی مانند ismodule، isclass، isfunction و ismethod را برای بررسی ماهیت یک شیء فراهم کرده است. این روش مطمئنتر از بررسی type() به صورت مستقیم است.
مثال ۱: بررسی توابع و کلاسها (قابل اجرا)
در این مثال یک تابع و یک کلاس تعریف کرده و نوع آنها را با inspect بررسی میکنیم.
مثال ۲: بررسی ماژولها (Snippet) گاهی نیاز دارید چک کنید آیا شیء پاس داده شده یک ماژول است یا خیر.
import inspect
import os
# این کد فقط یک قطعه کد است و به تنهایی اجرا نمیشود
def analyze_object(obj):
if inspect.ismodule(obj):
print("This is a module.")
else:
print("Not a module.")
مثال ۳: بررسی Generatorها (قابل اجرا) تشخیص اینکه آیا یک تابع، یک Generator برمیگرداند یا خیر.
۲. دسترسی به سورس کد و مستندات
یکی از جذابترین قابلیتهای inspect، امکان دریافت سورس کد اصلی یک تابع یا کلاس به صورت رشته (String) است.

مثال ۱: دریافت سورس کد (قابل اجرا)
تابع getsource دقیقاً کدی که نوشتهاید را برمیگرداند.
مثال ۲: دریافت Docstring و مسیر فایل (قابل اجرا)
توابع getdoc و getfile اطلاعات متادیتا را برمیگردانند.
مثال ۳: دریافت خطوط کد به صورت لیست (Static)
اگر بخواهید خط به خط پردازش کنید، از getsourcelines استفاده میشود.
import inspect
def sample():
return True
# خروجی شامل یک لیست از خطوط و شماره خط شروع است
lines, start_line = inspect.getsourcelines(sample)
۳. سلسله مراتب کلاسها (MRO)
متد getmro (Method Resolution Order) به شما نشان میدهد که یک کلاس از چه کلاسهای دیگری ارثبری کرده است و پایتون به چه ترتیبی متدها را جستجو میکند.
مثال ۱: مشاهده ارثبری ساده (قابل اجرا)
مثال ۲: استفاده در دیباگ (Snippet)
# کاربرد: زمانی که نمیدانید متد super() کدام کلاس را صدا میزند
def debug_inheritance(cls):
print(inspect.getmro(cls))
سطح پیشرفته (Professional Level)
در این سطح به سراغ تحلیل امضای توابع (Signatures)، بررسی پشته فراخوانی (Call Stack)، کار با توابع ناهمگام (Async) و مدیریت دکوریتورها میرویم.
۱. تحلیل Signature و پارامترها
برای فریمورکسازی (مثل کاری که FastAPI یا Django انجام میدهند)، باید بدانید یک تابع چه آرگومانهایی میگیرد، کدام اجباری هستند و مقادیر پیشفرض چیست. کلاس inspect.Signature این کار را انجام میدهد.
مثال ۱: استخراج نام و نوع پارامترها (قابل اجرا)
مثال ۲: Bind کردن آرگومانها (Static)
متد bind بررسی میکند که آیا آرگومانهای ورودی با امضای تابع مطابقت دارند یا خیر، بدون اینکه تابع را اجرا کند.
import inspect
def process(a, b):
return a + b
sig = inspect.signature(process)
# این خط بدون خطا اجرا میشود چون آرگومانها معتبرند
bound_args = sig.bind(10, 20)
# این خط خطا میدهد چون آرگومان b داده نشده است
# sig.bind(10) -> TypeError
مثال ۳: اعمال محدودیت روی نوع پارامتر (قابل اجرا) تشخیص پارامترهایی که فقط به صورت Keyword یا Positional باید ارسال شوند.
۲. بازرسی پشته (Stack Inspection)
با استفاده از stack() و currentframe() میتوانید ببینید برنامه در حال حاضر کجاست و چه کسی تابع فعلی را صدا زده است. این برای ساخت سیستمهای لاگبرداری حرفهای بسیار کاربرد دارد.
مثال ۱: پیدا کردن تابع فراخوانیکننده (Caller) (قابل اجرا)
مثال ۲: دسترسی به متغیرهای محلی Caller (Snippet) این کار خطرناک است اما برای دیباگرها لازم است.
import inspect
def spy():
frame = inspect.currentframe().f_back
# دسترسی به متغیرهای محلی تابعی که spy را صدا زده
print(frame.f_locals)
۳. کار با توابع Async و Coroutineها
در برنامهنویسی مدرن پایتون (Asyncio)، تشخیص اینکه یک تابع عادی است یا Coroutine بسیار مهم است.
مثال ۱: تشخیص توابع ناهمگام (قابل اجرا)
مثال ۲: بررسی Awaitable بودن (Snippet)
import inspect
# بررسی اینکه آیا یک شیء میتواند جلوی await قرار گیرد
def check_awaitable(obj):
if inspect.isawaitable(obj):
print("You can await this object.")
۴. مدیریت دکوریتورها (Unwrapping)
وقتی تابعی دکوریت میشود، متادیتای آن تغییر میکند. inspect.unwrap به شما اجازه میدهد به تابع اصلی (زیرین) دسترسی پیدا کنید.
مثال ۱: دسترسی به تابع اصلی پشت دکوریتور (قابل اجرا)
مثال ۲: زنجیره دکوریتورها (Static)
اگر چندین دکوریتور داشته باشید، unwrap به صورت بازگشتی تا رسیدن به تابع اصلی پیش میرود.
import inspect
# فرض کنید func توسط decorator1 و decorator2 محصور شده است
# original_func = inspect.unwrap(func)
# این کار آخرین لایه را برمیگرداند (تابع خالص)