TypeVar والفئات العامة وProtocol
عرّف أنواعاً عامة قابلة لإعادة الاستخدام، واستخدم التوريث البنيوي الفرعي مع Protocol
TypeVar والفئات العامة وProtocol درس مجاني في Python Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Python Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Python Academy 4 دروس في المجموع.
ما هو TypeVar؟
يعرّف TypeVar متغير نوع — وهو عنصر نائب يمكن أن يمثل أي نوع، ويمكن تقييده عند الحاجة. ويُستخدم في الدوال والفئات العامة.
from typing import TypeVar
T = TypeVar("T")
def identity(value: T) -> T:
return value
print(identity(42)) # int
print(identity("hello")) # strالدوال العامة
تتيح الدالة التي تستخدم TypeVar في أنواع المعاملات والقيم المعادة لـ mypy استنتاج نوع القيمة المعادة من نوع الوسيط.
from typing import TypeVar
T = TypeVar("T")
def first(items: list[T]) -> T:
return items[0]
x: int = first([1, 2, 3]) # mypy knows x is int
s: str = first(["a","b","c"]) # mypy knows s is strTypeVar المقيّد
مرّر قيود الأنواع إلى TypeVar لتقييد الأنواع المقبولة.
from typing import TypeVar
Numeric = TypeVar("Numeric", int, float)
def double(n: Numeric) -> Numeric:
return n * 2
print(double(5)) # 10
print(double(2.5)) # 5.0
# double("x") # mypy errorالفئات العامة
ورّث من Generic[T] لإنشاء فئة تعتمد معلمتها على متغير نوع.
from typing import Generic, TypeVar
T = TypeVar("T")
class Stack(Generic[T]):
def __init__(self) -> None:
self._items: list[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T:
return self._items.pop()
stack: Stack[int] = Stack()
stack.push(1)
print(stack.pop()) # 1متغيرات TypeVar متعددة
استخدم عدة متغيرات TypeVar لجعل فئة أو دالة تعتمد على نوعين مستقلين.
from typing import Generic, TypeVar
K = TypeVar("K")
V = TypeVar("V")
class Pair(Generic[K, V]):
def __init__(self, key: K, value: V) -> None:
self.key = key
self.value = value
p: Pair[str, int] = Pair("age", 30)
print(p.key, p.value) # age 30Protocol — التوريث الفرعي البنيوي
يعرّف Protocol واجهةً من خلال الأساليب والسمات التي يجب أن تحتوي عليها الفئة، دون اشتراط التوريث الصريح («الكتابة بأسلوب بطة، مع التحقق من النوع»).
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
def render(obj: Drawable) -> None:
obj.draw()
class Circle:
def draw(self) -> None:
print("Drawing circle")
render(Circle()) # works — Circle satisfies DrawableProtocol مع runtime_checkable
أضف @runtime_checkable إلى Protocol لتمكين عمليات التحقق isinstance() في وقت التشغيل.
from typing import Protocol, runtime_checkable
@runtime_checkable
class Closeable(Protocol):
def close(self) -> None: ...
class File:
def close(self) -> None: print("closed")
print(isinstance(File(), Closeable)) # TrueProtocol مقابل ABC
تتطلب ABCs توريثًا صريحًا (class Dog(Animal)). أما Protocols فتعمل بالمطابقة البنيوية؛ فإذا كانت الفئة تحتوي على الأساليب الصحيحة، فإنها تفي بالبروتوكول بغض النظر عن التوريث.
from typing import Protocol
from abc import ABC, abstractmethod
# ABC: nominal typing
class Printable(ABC):
@abstractmethod
def display(self) -> None: ...
# Protocol: structural typing
class Displayable(Protocol):
def display(self) -> None: ...TypeVar مع bound
يقيّد TypeVar("T", bound=BaseClass) T ليكون من نوع BaseClass أو من أي فئة فرعية له.
from typing import TypeVar
class Animal:
def speak(self) -> str: return "..."
A = TypeVar("A", bound=Animal)
def make_speak(animal: A) -> str:
return animal.speak()الاسم المستعار العام — Python 3.12
يقدم Python 3.12 تعليمة type لإنشاء أسماء مستعارة للأنواع بطريقة واضحة، وصيغة class Foo[T] للأنواع العامة دون استيراد TypeVar.
# Python 3.12+
type Vector = list[float]
type Matrix = list[Vector]
class Stack[T]:
def __init__(self) -> None: self._items: list[T] = []
def push(self, item: T) -> None: self._items.append(item)
def pop(self) -> T: return self._items.pop()نوع Self
يضع Self (من typing في 3.11+) تعليقًا على الأساليب التي تعيد الفئة الحالية، وهو مفيد في الواجهات المتسلسلة والفئات الفرعية.
from typing import Self
class Builder:
def __init__(self) -> None:
self.parts: list[str] = []
def add(self, part: str) -> Self:
self.parts.append(part)
return self
b = Builder().add("a").add("b")
print(b.parts) # ["a", "b"]تحقق سريع
ما الفرق الأساسي بين Protocol وABC في كتابة أنواع Python؟
مراجعة
ينشئ TypeVar عناصر نائبة للأنواع في الدوال والفئات العامة. وتُستخدم Generic[T] لجعل الفئات تعتمد على معلمة نوع. ويتيح Protocol التوريث الفرعي البنيوي دون توريث صريح. استخدم bound= أو قيود الأنواع على TypeVar لتقييد الأنواع المقبولة.
الأسئلة الشائعة
هل درس «TypeVar والفئات العامة وProtocol» مجاني؟
نعم — نص درس «TypeVar والفئات العامة وProtocol» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Python Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Python Academy 4 دروس في المجموع.
ماذا ستتعلم في «TypeVar والفئات العامة وProtocol»؟
عرّف أنواعاً عامة قابلة لإعادة الاستخدام، واستخدم التوريث البنيوي الفرعي مع Protocol تتمرن على Python Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Python Academy؟
لا تُشترط خبرة سابقة. Python Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «TypeVar والفئات العامة وProtocol»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Python Academy هذا؟
نعم. كل درس في Python Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- أساسيات تعليقات الأنواع
- الأنواع المعقدة: List وDict وOptional وUnion
- TypeVar والفئات العامة وProtocol
- تشغيل mypy وإصلاح أخطاء الأنواع