ویژگی تصویر

کتابخانه inspect در پایتون — راهنمای کامل برای بازتاب و بررسی کد زمان اجرا

  /  پایتون   /  کتابخانه inspect در پایتون
بنر تبلیغاتی الف

ماژول inspect یک ابزار قدرتمند در کتابخانه استاندارد پایتون است که امکان بازتاب (reflection) و بررسی ساختار کد در زمان اجرا را فراهم می‌کند. این ماژول برای دیباگ، تولید مستندات خودکار، تست‌ها، فریم‌ورک‌ها و ابزارهای توسعه بسیار مفید است.

چرا از inspect استفاده می‌کنیم؟

  • خواندن سورس یک تابع یا کلاس با getsource
  • دریافت پارامترها و امضای تابع با signature
  • پیدا کردن اعضای یک ماژول یا کلاس با getmembers
  • بررسی استک فراخوانی‌ها و اطلاعات فایل/شماره خط هنگام خطا با stack و getframeinfo

توابع پرکاربرد و کاربردشان

تابعکاربرد
inspect.getsource(obj)دریافت متن سورس شیء پایتون (در صورتی که در کد پایتون تعریف شده باشد)
inspect.signature(callable)دریافت امضای تابع/کلاس به صورت شیء Signature
inspect.getmembers(obj)فهرست اعضای یک ماژول/کلاس به همراه فیلتر قابل تنظیم
inspect.stack() / inspect.currentframe()بررسی استک فراخوانی‌ها و فریم‌ها برای دیباگ
inspect.isfunction / isclass / ismethodشناسایی نوع شیء

مثال‌های عملی

مثال: گرفتن سورس و امضا از یک تابع ساده

import inspect

def greet(name: str, excited: bool = False) -> str:
    """Return a greeting."""
    if excited:
        return f"Hello, {name}!"
    return "Hello, " + name

# get source
src = inspect.getsource(greet)

# get signature
sig = inspect.signature(greet)

print(src)
print(sig)

در این کد: ابتدا تابعی با آنوتیشن‌ها تعریف شده؛ سپس با inspect.getsource متن اصلی تابع گرفته می‌شود و با inspect.signature امضای آن (پارامترها و مقدار پیش‌فرض) نمایش داده می‌شود. این برای تولید مستندات یا وِریفای پارامترها مفید است.

استفاده از Signature برای بررسی و بایند کردن آرگومان‌ها

from inspect import signature

def func(a, b=2, *args, **kwargs):
    pass

sig = signature(func)
bound = sig.bind(1, 3, 4, x=5)  # will raise TypeError if mismatch
print(bound.arguments)

توضیح: با متد bind می‌توان آرگومان‌ها را به امضای تابع متصل کرد و بررسی کرد که آیا آرگومان‌ها معتبرند یا نه. این کاربرد در پیاده‌سازی ولویدیشن پارامترها در دکوراتورها یا فریم‌ورک‌ها بسیار کاربردی است.

بازتاب اعضای یک کلاس یا ماژول

import inspect

class MyClass:
    def method(self): pass
    @staticmethod
    def stat(): pass

print(inspect.getmembers(MyClass, inspect.isfunction))

توضیح: getmembers لیستی از اعضا برمی‌گرداند؛ با فیلترهایی مثل inspect.isfunction یا inspect.ismethod می‌توان فقط توابع یا متدها را گرفت. این روش برای تولید خودکار لیست API یا تست‌های پویا مفید است.

بررسی استک برای دیباگ و لاگ‌گیری

import inspect

def caller():
    frame = inspect.currentframe()
    try:
        # caller frame is frame.f_back
        info = inspect.getframeinfo(frame.f_back)
        print(f"Called from {info.filename}:{info.lineno}")
    finally:
        del frame  # avoid reference cycle

def a():
    caller()

a()

توضیح: این نمونه با گرفتن فریم فعلی و رفتن یک فریم به عقب، فایل و شماره خط فراخوان را چاپ می‌کند. مفید برای لاگ‌ کردن منبع فراخوانی تابع‌ها هنگام ديباگ یا تولید گزارش خطا است. حذف مرجع فریم (del frame) برای جلوگیری از حلقه مرجع و نشت حافظه توصیه می‌شود.

ملاحظات و محدودیت‌ها

  • توابع و کلاس‌هایی که در کد بایت‌کامپایل‌شده یا به‌صورت Built-in (مثلاً نوشته‌شده در C) هستند، معمولاً getsource برای آنها کار نمی‌کند.
  • در زمان اجرای فایل‌هایی که به‌صورت فشرده یا بسته توزیع شده‌اند، ممکن است اطلاعات موقعیت فایل یا سورس در دسترس نباشد.
  • استفاده از بررسی فریم‌ها می‌تواند منجر به افزایش مصرف حافظه یا حفظ ارجاعات ناخواسته شود؛ پس در حلقه‌های داغ یا پرکار نباید افراط شود.

نکات پیشرفته و توصیه‌های کارشناسان

  • برای حفظ امضا در دکوراتورها از functools.wraps استفاده کنید تا inspect.signature رفتار درست داشته باشد.
  • در پیاده‌سازی ابزارهای تست و فریم‌ورک‌ها از signature.bind برای ولیدیشن پارامترها بهره ببرید.
  • برای پردازش آنتوتیشن‌ها و نوع‌سنجی پویا، متدهای Signature.parameters و inspect.get_annotations بسیار مفیدند.
  • برای async/await از inspect.iscoroutinefunction و iscoroutine استفاده کنید تا رفتار توابع ناهمزمان را تشخیص دهید.

نمونه: دکوراتور با بررسی امضا و ولیدیشن ساده

import functools
import inspect

def enforce_types(func):
    sig = inspect.signature(func)
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        bound = sig.bind(*args, **kwargs)
        for name, value in bound.arguments.items():
            param = sig.parameters[name]
            if param.annotation is not inspect._empty and not isinstance(value, param.annotation):
                raise TypeError(f"Parameter {name} must be {param.annotation}")
        return func(*args, **kwargs)
    return wrapper

@enforce_types
def add(a: int, b: int) -> int:
    return a + b

print(add(1, 2))
# add(1, "x")  # raises TypeError

توضیح: این دکوراتور با کمک inspect.signature و bind آرگومان‌ها را متصل کرده و با استفاده از آنوتیشن‌ها نوع پارامترها را بررسی می‌کند. همچنین از functools.wraps برای حفظ متادیتا و امضا استفاده شده است.

خلاصه و جمع‌بندی

ماژول inspect ابزاری ضروری برای توسعه‌دهندگان پایتون است که به کمک آن می‌توان کد را در زمان اجرا بررسی، مستندسازی و اعتبارسنجی کرد. با اینکه محدودیت‌هایی (مثل عدم دسترسی به سورس توابع نوشته‌شده در C) وجود دارد، اما ترکیب قابلیت‌های signature، getsource، getmembers و توابع استک امکان ساخت ابزارهای قدرتمند و خودکار را فراهم می‌سازد.

در صورت نیاز به مثال‌های بیشتر برای مورد استفاده خاص (مثل تولید مستندات HTML خودکار، تست‌های پویا یا تحلیل کدهای Async)، می‌توان نمونه‌های اختصاصی‌تر ارائه داد.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: