الدرس 11 من 20

الدوال والفئات

Dataclasses

3 دقيقة للقراءة

Dataclasses تقلل الكود المتكرر عند إنشاء فئات تخزن البيانات بشكل أساسي. تولّد تلقائياً __init__ و __repr__ وطرق المقارنة.

Dataclass أساسي

from dataclasses import dataclass

@dataclass
class Message:
    role: str
    content: str

# يولّد __init__ تلقائياً
msg = Message(role="user", content="مرحباً!")

# يولّد __repr__ تلقائياً
print(msg)  # Message(role='user', content='مرحباً!')

# الوصول للسمات يعمل بشكل طبيعي
print(msg.role)     # "user"
print(msg.content)  # "مرحباً!"

المقارنة: فئة عادية مقابل Dataclass

# فئة عادية (مطوّلة)
class MessageOld:
    def __init__(self, role, content):
        self.role = role
        self.content = content

    def __repr__(self):
        return f"Message(role='{self.role}', content='{self.content}')"

    def __eq__(self, other):
        return self.role == other.role and self.content == other.content

# Dataclass (موجزة)
@dataclass
class Message:
    role: str
    content: str
# جميع الطرق أعلاه تُولّد تلقائياً!

القيم الافتراضية

from dataclasses import dataclass
from typing import Optional

@dataclass
class ChatConfig:
    model: str = "gpt-4"
    temperature: float = 0.7
    max_tokens: int = 1000
    stream: bool = False

# استخدم الافتراضيات
config1 = ChatConfig()

# تجاوز بعض القيم
config2 = ChatConfig(model="claude-3-opus", temperature=0.9)

الحقول مع Default Factory

للافتراضيات القابلة للتغيير (القوائم، القواميس)، استخدم field():

from dataclasses import dataclass, field
from typing import List, Dict

@dataclass
class Agent:
    name: str
    model: str = "gpt-4"
    # خطأ: history: List[Dict] = []  # مشتركة بين المثيلات!
    # صحيح: استخدم field مع default_factory
    history: List[Dict] = field(default_factory=list)
    config: Dict = field(default_factory=dict)

agent1 = Agent(name="الوكيل1")
agent2 = Agent(name="الوكيل2")

agent1.history.append({"msg": "مرحباً"})
print(agent1.history)  # [{"msg": "مرحباً"}]
print(agent2.history)  # [] (قائمة منفصلة)

Frozen Dataclasses (غير قابلة للتغيير)

from dataclasses import dataclass

@dataclass(frozen=True)
class ApiKey:
    provider: str
    key: str

key = ApiKey(provider="openai", key="sk-...")
# key.provider = "anthropic"  # خطأ! لا يمكن تعديل dataclass مجمدة

مثال عملي للذكاء الاصطناعي

from dataclasses import dataclass, field
from typing import List, Optional

@dataclass
class ToolCall:
    name: str
    arguments: dict

@dataclass
class AgentResponse:
    content: str
    tool_calls: List[ToolCall] = field(default_factory=list)
    finish_reason: str = "stop"
    usage: Optional[dict] = None

@dataclass
class ConversationTurn:
    user_message: str
    assistant_response: AgentResponse
    timestamp: float = field(default_factory=lambda: __import__('time').time())

# هياكل بيانات نظيفة وآمنة من حيث النوع
response = AgentResponse(
    content="دعني أبحث عن ذلك.",
    tool_calls=[ToolCall(name="search", arguments={"query": "بايثون"})]
)

بعد ذلك، سنتعلم كيفية معالجة الأخطاء بشكل أنيق في بايثون. :::

اختبار

الوحدة 3: الدوال والفئات

خذ الاختبار