رفتن به محتوای اصلی
برنامه‌سازی پیشرفته با پایتون درس‌نامهٔ آزاد
درس پیشرفته ۲۵ دقیقه

بازتاب و مباحث تکمیلی

درون‌نگری با type و inspect، اعلان‌ها به‌مثابه فراداده، تزئین‌کننده‌ها، بستارها و enum.

هدف این درس

بتوانی در زمان اجرا ساختار شیء را کاوش کنی و با تزئین‌کننده رفتار را تمیز توسعه دهی.

در این مطلب ۴

بازتاب (reflection) یعنی «برنامه‌ای که خودش را می‌خواند»: در زمان اجرا بپرسی این شیء چیست، چه ویژگی‌هایی دارد و چه متدهایی می‌فهمد. در پایتون این کار روزمره است، نه جادوی پیشرفته.

جعبه‌ابزار درون‌نگری

class Book:
    """کتاب سادهٔ کتابخانه."""
    def __init__(self, title):
        self.title = title

    def describe(self):
        return f"کتاب: {self.title}"

b = Book("شازده کوچولو")
print(type(b))            # <class 'Book'>
print(isinstance(b, Book))  # True
print(hasattr(b, "title"))  # True
print(getattr(b, "title"))  # شازده کوچولو
print([m for m in dir(b) if not m.startswith("_")])

برای کاوش عمیق‌تر ماژول inspect است: inspect.signature امضای تابع را می‌دهد و inspect.getsource (وقتی سورس در دسترس باشد) کدش را. اعلان‌های نوع هم با __annotations__ در زمان اجرا خواندنی‌اند — یعنی نوع‌ها فقط برای mypy نیستند، فرادادهٔ اجرایی‌اند.

بستار: تابعی که محیطش را یادش می‌ماند

def make_counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc

c = make_counter()
print(c())  # 1
print(c())  # 2 — count بین فراخوانی‌ها زنده ماند

بستار همان کاری را می‌کند که در جاوا «کلاس داخلی ناشناس» می‌کرد، ولی با یک تابع ساده. هر جا وسوسه شدی کلاسِ تک‌متده بسازی، اول بپرس: «یک بستار کافی نیست؟»

تزئین‌کننده: توسعهٔ رفتار بدون دست‌بردن در تابع

import functools, time

def timed(func):
    @functools.wraps(func)  # نام و مستند تابع اصلی حفظ شود
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        print(f"{func.__name__} در {time.perf_counter()-start:.4f} ثانیه")
        return result
    return wrapper

@timed
def slow_search(n):
    return sum(range(n))

enum: انتخاب‌های نام‌دار

from enum import Enum, auto

class OrderStatus(Enum):
    PENDING = auto()
    PAID = auto()
    SHIPPED = auto()
    CANCELLED = auto()

def advance(status):
    if status is OrderStatus.PAID:
        return OrderStatus.SHIPPED
    return status

رشته‌های پراکنده («paid»، «Paid»، «PAID») منبع باگ‌اند؛ enum انتخاب‌ها را یکی و قابل بررسی می‌کند.

سنجش فهم — بازتاب

۰ از ۲ پاسخ داده شده

  1. تفاوت getattr با دسترسی مستقیم ویژگی چیست؟
  2. تزئین‌کننده بدون functools.wraps از نظر رفتاری کامل است و فقط ظاهر فرق می‌کند.(درست / نادرست)

اول به همهٔ پرسش‌ها پاسخ دهید، بعد بررسی کنید.

مطالب مرتبط

از همین بخش و با برچسب‌های مشترک

این مطلب را خواندید؟ آن را علامت بزنید تا پیشرفت شما روی همین دستگاه ذخیره شود.

وضعیت پیشرفت برای بازتاب و مباحث تکمیلی