समझें कि एनोटेशन रनटाइम पर असल में क्या करते हैं, और frozen, slots तथा default_factory के साथ dataclasses का पूरा लाभ उठाएँ।
इस पाठ को Kodokon में खोलेंटाइप एनोटेशन मेटाडेटा हैं, बाधाएँ नहीं: इंटरप्रेटर उन्हें __annotations__ में संग्रहीत करता है और रनटाइम पर कभी नहीं जाँचता। जाँचना mypy या pyright जैसे स्टैटिक एनालाइज़र का काम है, निष्पादन से पहले। इसका सीधा परिणाम: गलत टाइप वाला प्रोग्राम बिना किसी शिकायत के चलता है - और यह जानबूझकर ऐसा ही है। ग्रैजुअल टाइपिंग आपको किसी मौजूदा कोडबेस को थोड़ा-थोड़ा करके, बिना कुछ तोड़े, एनोटेट करने देती है।
from typing import get_type_hints
def add(a: int, b: int) -> int:
return a + b
print(add("py", "thon"))
print(add.__annotations__)
print(get_type_hints(add))Python 3.9 से, बिल्ट-इन टाइप सीधे जेनेरिक हैं: typing.List इम्पोर्ट किए बिना list[int] या dict[str, float] लिखें। 3.10 से यूनियन int | None लिखे जाते हैं। इनपुट टाइप को आउटपुट टाइप से जोड़ने के लिए TypeVar का उपयोग करें - Python 3.12 तो संक्षिप्त सिंटैक्स def first[T](items: list[T]) -> T भी देता है। एक बिंदु जिसे अक्सर अनदेखा किया जाता है: from __future__ import annotations हर एनोटेशन को आलसी बना देता है (स्ट्रिंग के रूप में संग्रहीत), जिससे आगे परिभाषित क्लासों का संदर्भ देना संभव होता है और इम्पोर्ट के समय की लागत घटती है।
from collections.abc import Iterable, Iterator
from typing import TypeVar
T = TypeVar("T")
def dedupe(items: Iterable[T]) -> Iterator[T]:
seen: set[T] = set()
for item in items:
if item not in seen:
seen.add(item)
yield item
print(list(dedupe([3, 1, 3, 2, 1])))from dataclasses import dataclass, field
@dataclass(frozen=True, slots=True)
class Point:
x: float
y: float
@dataclass
class Basket:
items: list[str] = field(default_factory=list)
total: int = 0
def __post_init__(self) -> None:
self.total = len(self.items)
point = Point(1.0, 2.0)
print(point, hash(point))
print(Basket(["book", "pen"]))तीन पैरामीटर @dataclass को प्रोडक्शन-स्तर का औज़ार बना देते हैं। frozen=True इंस्टेंस को अपरिवर्तनीय बनाता है और, जनरेट की गई समानता के साथ मिलकर, हैशेबल भी - डिक्शनरी की कुंजी के रूप में प्रयोग योग्य। slots=True (Python 3.10+) प्रति-इंस्टेंस __dict__ हटा देता है: कम मेमोरी, तेज़ एट्रिब्यूट एक्सेस, और कोई भी अप्रत्याशित एट्रिब्यूट असाइनमेंट विफल हो जाता है। अंत में kw_only=True स्पष्ट कीवर्ड कॉल को अनिवार्य करता है। __post_init__ वह जगह है जहाँ इनवेरिएंट और व्युत्पन्न फ़ील्ड रखे जाते हैं। किसी साधारण अपरिवर्तनीय समुच्चय के लिए NamedTuple अब भी समझदारी है; जैसे ही व्यवहार या सत्यापन आ जाए, dataclass को प्राथमिकता दें।
(a: int, b: int) -> int एनोटेट हो और आप add('py', 'thon') कॉल करें, तो रनटाइम पर क्या होता है?items: list[str] = [] क्यों वर्जित है?list[str] किसी फ़ील्ड के लिए मान्य एनोटेशन नहीं हैfrozen=True किसी dataclass के साथ क्या करता है?