کتابخانه 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)، میتوان نمونههای اختصاصیتر ارائه داد.
آیا این مطلب برای شما مفید بود ؟




