خانه / آموزش‌ها / آموزش جامع ماژول inspect در پایتون (Introspection)

آموزش جامع ماژول inspect در پایتون (Introspection)

🐍 HomeOfPython
|
📅 1404/10/18

ماژول inspect یکی از قدرتمندترین ابزارهای پایتون برای درون‌نگری (Introspection) است. درون‌نگری به این معناست که برنامه می‌تواند در زمان اجرا (Runtime) اطلاعاتی درباره اشیاء موجود در حافظه (مانند توابع، کلاس‌ها، ماژول‌ها و فریم‌های پشته) کسب کند. این قابلیت برای ساخت فریم‌ورک‌ها، ابزارهای دیباگ و تولید مستندات خودکار حیاتی است.

سطح مقدماتی (Beginner Level)

در سطح مقدماتی، یاد می‌گیریم چگونه نوع اشیاء را بررسی کنیم، به سورس کد آن‌ها دسترسی پیدا کنیم و سلسله مراتب کلاس‌ها را مشاهده کنیم.

۱. بررسی نوع اشیاء (Type Checking)

پایتون توابع متعددی مانند ismodule، isclass، isfunction و ismethod را برای بررسی ماهیت یک شیء فراهم کرده است. این روش مطمئن‌تر از بررسی type() به صورت مستقیم است.

مثال ۱: بررسی توابع و کلاس‌ها (قابل اجرا) در این مثال یک تابع و یک کلاس تعریف کرده و نوع آن‌ها را با inspect بررسی می‌کنیم.

Python

مثال ۲: بررسی ماژول‌ها (Snippet) گاهی نیاز دارید چک کنید آیا شیء پاس داده شده یک ماژول است یا خیر.

python
import inspect
import os

# این کد فقط یک قطعه کد است و به تنهایی اجرا نمی‌شود
def analyze_object(obj):
    if inspect.ismodule(obj):
        print("This is a module.")
    else:
        print("Not a module.")

مثال ۳: بررسی Generatorها (قابل اجرا) تشخیص اینکه آیا یک تابع، یک Generator برمی‌گرداند یا خیر.

Python

۲. دسترسی به سورس کد و مستندات

یکی از جذاب‌ترین قابلیت‌های inspect، امکان دریافت سورس کد اصلی یک تابع یا کلاس به صورت رشته (String) است.

نمودار دسترسی به سورس

مثال ۱: دریافت سورس کد (قابل اجرا) تابع getsource دقیقاً کدی که نوشته‌اید را برمی‌گرداند.

Python

مثال ۲: دریافت Docstring و مسیر فایل (قابل اجرا) توابع getdoc و getfile اطلاعات متادیتا را برمی‌گردانند.

Python

مثال ۳: دریافت خطوط کد به صورت لیست (Static) اگر بخواهید خط به خط پردازش کنید، از getsourcelines استفاده می‌شود.

python
import inspect

def sample():
    return True

# خروجی شامل یک لیست از خطوط و شماره خط شروع است
lines, start_line = inspect.getsourcelines(sample)

۳. سلسله مراتب کلاس‌ها (MRO)

متد getmro (Method Resolution Order) به شما نشان می‌دهد که یک کلاس از چه کلاس‌های دیگری ارث‌بری کرده است و پایتون به چه ترتیبی متدها را جستجو می‌کند.

مثال ۱: مشاهده ارث‌بری ساده (قابل اجرا)

Python

مثال ۲: استفاده در دیباگ (Snippet)

python
# کاربرد: زمانی که نمی‌دانید متد super() کدام کلاس را صدا می‌زند
def debug_inheritance(cls):
    print(inspect.getmro(cls))

سطح پیشرفته (Professional Level)

در این سطح به سراغ تحلیل امضای توابع (Signatures)، بررسی پشته فراخوانی (Call Stack)، کار با توابع ناهمگام (Async) و مدیریت دکوریتورها می‌رویم.

۱. تحلیل Signature و پارامترها

برای فریم‌ورک‌سازی (مثل کاری که FastAPI یا Django انجام می‌دهند)، باید بدانید یک تابع چه آرگومان‌هایی می‌گیرد، کدام اجباری هستند و مقادیر پیش‌فرض چیست. کلاس inspect.Signature این کار را انجام می‌دهد.

مثال ۱: استخراج نام و نوع پارامترها (قابل اجرا)

Python

مثال ۲: Bind کردن آرگومان‌ها (Static) متد bind بررسی می‌کند که آیا آرگومان‌های ورودی با امضای تابع مطابقت دارند یا خیر، بدون اینکه تابع را اجرا کند.

python
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 باید ارسال شوند.

Python

۲. بازرسی پشته (Stack Inspection)

با استفاده از stack() و currentframe() می‌توانید ببینید برنامه در حال حاضر کجاست و چه کسی تابع فعلی را صدا زده است. این برای ساخت سیستم‌های لاگ‌برداری حرفه‌ای بسیار کاربرد دارد.

مثال ۱: پیدا کردن تابع فراخوانی‌کننده (Caller) (قابل اجرا)

Python

مثال ۲: دسترسی به متغیرهای محلی Caller (Snippet) این کار خطرناک است اما برای دیباگرها لازم است.

python
import inspect

def spy():
    frame = inspect.currentframe().f_back
    # دسترسی به متغیرهای محلی تابعی که spy را صدا زده
    print(frame.f_locals)

۳. کار با توابع Async و Coroutineها

در برنامه‌نویسی مدرن پایتون (Asyncio)، تشخیص اینکه یک تابع عادی است یا Coroutine بسیار مهم است.

مثال ۱: تشخیص توابع ناهمگام (قابل اجرا)

Python

مثال ۲: بررسی Awaitable بودن (Snippet)

python
import inspect

# بررسی اینکه آیا یک شیء می‌تواند جلوی await قرار گیرد
def check_awaitable(obj):
    if inspect.isawaitable(obj):
        print("You can await this object.")

۴. مدیریت دکوریتورها (Unwrapping)

وقتی تابعی دکوریت می‌شود، متادیتای آن تغییر می‌کند. inspect.unwrap به شما اجازه می‌دهد به تابع اصلی (زیرین) دسترسی پیدا کنید.

مثال ۱: دسترسی به تابع اصلی پشت دکوریتور (قابل اجرا)

Python

مثال ۲: زنجیره دکوریتورها (Static) اگر چندین دکوریتور داشته باشید، unwrap به صورت بازگشتی تا رسیدن به تابع اصلی پیش می‌رود.

python
import inspect

# فرض کنید func توسط decorator1 و decorator2 محصور شده است
# original_func = inspect.unwrap(func)
# این کار آخرین لایه را برمی‌گرداند (تابع خالص)