Python के ऑब्जेक्ट मॉडल में महारत हासिल करें: __eq__/__hash__ का अनुबंध, NotImplemented वैल्यू, कॉन्टेक्स्ट मैनेजर और Protocol के साथ स्ट्रक्चरल टाइपिंग।
इस पाठ को Kodokon में खोलेंPython में, हर ऑपरेटर, हर रूपांतरण, हर with कथन किसी विशेष मेथड से होकर गुज़रता है: a == b a.__eq__(b) को कॉल करता है, len(x) x.__len__() को कॉल करता है। __repr__ - डेवलपर के लिए बनी असंदिग्ध प्रस्तुति, जो डीबगर में और लिस्ट के भीतर दिखती है - को __str__ से अलग करना ध्यान रखें, जो अंतिम उपयोगकर्ता के लिए है। यदि __str__ अनुपस्थित हो, तो Python __repr__ पर लौट आता है: इसलिए हमेशा पहले __repr__ लागू करें, आदर्श रूप से ऐसे रूप में जिससे ऑब्जेक्ट को दोबारा बनाया जा सके।
class Money:
def __init__(self, amount: int, currency: str):
self.amount = amount
self.currency = currency
def __repr__(self) -> str:
return f"Money({self.amount!r}, {self.currency!r})"
def __eq__(self, other: object) -> bool:
if not isinstance(other, Money):
return NotImplemented
return (self.amount, self.currency) == (
other.amount, other.currency)
print(Money(10, "EUR") == Money(10, "EUR"))
print(Money(10, "EUR") == "10 EUR")NotImplemented लौटाना (वह वैल्यू, जिसे NotImplementedError अपवाद से भ्रमित न करें) ऑपरेटर वार्ता प्रोटोकॉल को सक्रिय करता है: Python तब उलटी क्रिया other.__eq__(self) आज़माता है, और अंतिम उपाय के रूप में ही False निष्कर्ष निकालता है। सीधे False लौटाना उस वार्ता को छोटा कर देता और सबक्लासों या तीसरे पक्ष के उन टाइप के साथ तुलना तोड़ देता जो असल में उत्तर देना जानते होते।
import time
class Timer:
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, exc_type, exc, tb):
stop = time.perf_counter()
self.elapsed = stop - self.start
return False
with Timer() as timer:
sum(range(1_000_000))
print(f"{timer.elapsed:.4f} s")यदि __exit__ True लौटाता है, तो वर्तमान अपवाद दबा दिया जाता है - contextlib.suppress ठीक इसी तरह काम करता है। पूरी क्लास लिखने से बचने के लिए, @contextlib.contextmanager किसी जनरेटर को कॉन्टेक्स्ट मैनेजर में बदल देता है: yield से पहले का कोड __enter__ की भूमिका निभाता है, उसके बाद का कोड (आदर्श रूप से किसी finally में) __exit__ की। ऑब्जेक्ट मॉडल का एक और स्तंभ: typing मॉड्यूल के Protocol टाइप डक टाइपिंग को औपचारिक रूप देते हैं - कोई क्लास तब संगत होती है जब वह सही मेथड उजागर करती है, बिना किसी घोषित विरासत के।
from typing import Protocol, runtime_checkable
@runtime_checkable
class Closable(Protocol):
def close(self) -> None: ...
class Session:
def close(self) -> None:
print("session closed")
def shutdown(resource: Closable) -> None:
resource.close()
shutdown(Session())
print(isinstance(Session(), Closable))__eq__ में, जब आपका सामना ऐसे टाइप से हो जिससे आप तुलना नहीं कर सकते, तो क्या लौटाना चाहिए?__hash__ को छुए बिना __eq__ जोड़ते हैं। इसका परिणाम क्या है?True लौटाने वाले __exit__ मेथड का क्या अर्थ है?