आम तौर पर, @yak ने अपनी टिप्पणी में उल्लेख किए गए कारणों के लिए यह एक अच्छा विचार नहीं है। आप मूल रूप से ऐसे वैध तर्कों की आपूर्ति करने से उपयोगकर्ता को रोक रहे हैं जिनके पास सही गुण/व्यवहार है, लेकिन आप विरासत के पेड़ में नहीं हैं, जिनमें आप हार्ड-कोड किए गए हैं।
अलग-अलग अस्वीकरण, आप जो भी प्रयास कर रहे हैं उसके लिए कुछ विकल्प उपलब्ध हैं कर। मुख्य मुद्दा यह है कि पायथन में कोई निजी विशेषता नहीं है। तो यदि आपके पास सिर्फ एक सादा पुराना ऑब्जेक्ट संदर्भ है, तो self._a
कहें, आप गारंटी नहीं दे सकते कि उपयोगकर्ता इसे सीधे सेट नहीं करेगा, भले ही आपने एक सेटटर प्रदान किया हो जो इसके लिए जांच कर रहा हो। नीचे दिए गए विकल्प दर्शाते हैं कि प्रकार की जांच वास्तव में कैसे लागू करें।
अवहेलना __setattr__
यह विधि केवल एक (बहुत) गुण है कि आप करने के लिए ऐसा करने की छोटी संख्या के लिए सुविधाजनक हो जाएगा। __setattr__
विधि तब होती है जब आप नियमित विशेषता निर्दिष्ट करने के लिए डॉट नोटेशन का उपयोग करते हैं। उदाहरण के लिए,
class A:
def __init__(self, a0):
self.a = a0
अब हम A().a = 32
करते हैं, यह A().__setattr__('a', 32)
under the hood कहेंगे। वास्तव में, self.a = a0
__init__
में self.__setattr__
का भी उपयोग करता है। आप प्रकार की जांच लागू करने के लिए इस का उपयोग कर सकते हैं:
class A:
def __init__(self, a0):
self.a = a0
def __setattr__(self, name, value):
if name == 'a' and not isinstance(value, int):
raise TypeError('A.a must be an int')
super().__setattr__(name, value)
इस विधि का नुकसान आप (किसी निश्चित प्रकार के लिए कई नामों की जाँच करने के लिए या if name in ...
) प्रत्येक प्रकार आप जाँच करना चाहते हैं के लिए एक अलग if name == ...
है करना है । इसका फायदा यह है कि उपयोगकर्ता को टाइप चेक को रोकने के लिए लगभग असंभव बनाने का यह सबसे सरल तरीका है।
(आमतौर पर एक एनोटेशन का उपयोग करके) एक संपत्ति
गुण ऑब्जेक्ट की जानकारी देता वस्तु के साथ अपने सामान्य विशेषता की जगह हो। वर्णनकर्ताओं के पास __get__
और __set__
विधियां हो सकती हैं जो अंतर्निहित विशेषता का उपयोग कैसे करती हैं अनुकूलित करें। यह if
शाखा __setattr__
में ले जाने और इसे उस विधि में डालने जैसा है जो केवल उस विशेषता के लिए चलाएगा। ही बात कर के
class A:
def __init__(self, a0):
self.a = a0
@property
def a(self):
return self._a
@a.setter
def a(self, value):
if not ininstance(value, int):
raise TypeError('A.a must be an int')
self._a = value
एक थोड़ा अलग तरीके से @ jsbueno के जवाब में पाया जा सकता: यहाँ एक उदाहरण है।
एक संपत्ति का उपयोग करते समय इस तरह निफ्टी है और ज्यादातर समस्या हल करती है, यह कुछ मुद्दों को प्रस्तुत करती है। पहला यह है कि आपके पास "निजी" _a
विशेषता है जो उपयोगकर्ता आपके प्रकार की जांच को बाईपास करके सीधे संशोधित कर सकता है। सादे गेटर और सेटर का उपयोग करने के बारे में यह लगभग एक ही समस्या है, सिवाय इसके कि अब a
दृश्यों के पीछे सेटटर पर रीडायरेक्ट करने वाले "सही" विशेषता के रूप में सुलभ है, जिससे उपयोगकर्ता _a
के साथ गड़बड़ कर सकता है। दूसरा मुद्दा यह है कि संपत्ति को पढ़ने-लिखने के रूप में काम करने के लिए आपके पास एक अनिवार्य गेटटर है। ये मुद्दे this प्रश्न का विषय हैं।
एक सच सेटर केवल डिस्क्रिप्टर
यह समाधान शायद सबसे मजबूत समग्र है बनाएँ। यह ऊपर उल्लिखित प्रश्न के लिए accepted answer में सुझाया गया है। असल में, एक संपत्ति है, जो तामझाम और उपयुक्तता कि आप में से छुटकारा नहीं मिल रहा का एक समूह है उपयोग करने के बजाय, अपने खुद के वर्णनकर्ता एनोटेशन बना सकते हैं और उपयोग करने वाले सभी गुण है कि प्रकार की जाँच की आवश्यकता के लिए:
class SetterProperty:
def __init__(self, func, doc=None):
self.func = func
self.__doc__ = doc if doc is not None else func.__doc__
def __set__(self, obj, value):
return self.func(obj, value)
class A:
def __init__(self, a0):
self.a = a0
@SetterProperty
def a(self, value):
if not ininstance(value, int):
raise TypeError('A.a must be an int')
self.__dict__['a'] = value
सेटर stashes वास्तविक मूल्य सीधे __dict__
में उदाहरण के लिए अनिश्चित काल तक खुद को पुनः प्राप्त करने से बचने के लिए। इससे स्पष्ट गेटर की आपूर्ति किए बिना विशेषता का मूल्य प्राप्त करना संभव हो जाता है। चूंकि वर्णनकर्ता a
में __get__
विधि नहीं है, इसलिए खोज तब तक जारी रहेगी जब तक कि यह __dict__
में विशेषता नहीं पाती। यह सुनिश्चित करता है कि सभी सेट डिस्क्रिप्टर/सेटर के माध्यम से जाते हैं जबकि विशेषता मान तक सीधे पहुंच की अनुमति मिलती है।
आप गुण इस तरह एक जांच की आवश्यकता है कि की एक बड़ी संख्या है, तो आप वर्णनकर्ता के __set__
विधि में लाइन self.__dict__['a'] = value
स्थानांतरित कर सकते हैं:
class ValidatedSetterProperty:
def __init__(self, func, name=None, doc=None):
self.func = func
self.__name__ = name if name is not None else func.__name__
self.__doc__ = doc if doc is not None else func.__doc__
def __set__(self, obj, value):
ret = self.func(obj, value)
obj.__dict__[self.__name__] = value
class A:
def __init__(self, a0):
self.a = a0
@ValidatedSetterProperty
def a(self, value):
if not ininstance(value, int):
raise TypeError('A.a must be an int')
अद्यतन
Python3.6 करता है आपके लिए लगभग बॉक्स के बाहर: https://docs.python.org/3.6/whatsnew/3.6.html#pep-487-descriptor-protocol-enhancements
टीएल; डीआर
टाइप-चेकिंग की आवश्यकता वाले बहुत कम गुणों के लिए, सीधे __setattr__
ओवरराइड करें। बड़ी संख्या में विशेषताओं के लिए, उपरोक्त दिखाए गए सेटटर-केवल वर्णनकर्ता का उपयोग करें। इस प्रकार के आवेदन के लिए सीधे गुणों का उपयोग करने से हल होने की तुलना में अधिक समस्याएं उत्पन्न होती हैं।
पाइथोनिक तरीका कक्षा को उचित रूप से दस्तावेज करना है। यदि गलत ऑब्जेक्ट प्रकार सेट किया गया है, तो कोड वैसे भी असफल हो जाएगा। दूसरी तरफ उपयोगकर्ता एक ऐसे प्रकार का उपयोग कर सकता है जो आपके 'इंस्टेंसेंस' चेक को पास नहीं करेगा लेकिन अन्यथा ठीक है (बतख टाइपिंग)। – yak