गेटर्स और सेटरर्स के लिए @प्रॉपर्टी का उपयोग करना


727

यहाँ एक शुद्ध पायथन-विशिष्ट डिज़ाइन प्रश्न है:

class MyClass(object):
    ...
    def get_my_attr(self):
        ...

    def set_my_attr(self, value):
        ...

तथा

class MyClass(object):
    ...        
    @property
    def my_attr(self):
        ...

    @my_attr.setter
    def my_attr(self, value):
        ...

अजगर हमें या तो इसे करने की अनुमति देता है। यदि आप एक पायथन कार्यक्रम डिजाइन करेंगे, तो आप किस दृष्टिकोण का उपयोग करेंगे और क्यों?

जवाबों:


613

गुणों को प्राथमिकता दें । यह है कि वे वहाँ के लिए क्या कर रहे हैं

कारण यह है कि पायथन में सभी विशेषताएँ सार्वजनिक हैं। अंडरस्कोर या दो के साथ नाम शुरू करना सिर्फ एक चेतावनी है कि दी गई विशेषता एक कार्यान्वयन विवरण है जो कोड के भविष्य के संस्करणों में समान नहीं रह सकता है। यह आपको वास्तव में उस विशेषता को प्राप्त करने या स्थापित करने से नहीं रोकता है। इसलिए, मानक विशेषता पहुंच सामान्य है, पाइथोनिक तरीका है, अच्छी तरह से, अभिगम विशेषताओं।

गुणों का लाभ यह है कि वे विशेषता पहुंच के लिए समान रूप से समान हैं, इसलिए आप क्लाइंट कोड में कोई बदलाव किए बिना एक से दूसरे में बदल सकते हैं। आपके पास एक वर्ग का एक संस्करण भी हो सकता है जो गुणों का उपयोग करता है (जैसे, कोड-बाय-कॉन्ट्रैक्ट या डीबगिंग के लिए) और एक जो उत्पादन के लिए नहीं है, जो कोड का उपयोग किए बिना इसे बदल देता है। उसी समय, आपको हर चीज के लिए गेटर्स और सेटर लिखने की ज़रूरत नहीं है, अगर आपको बाद में बेहतर नियंत्रण की आवश्यकता हो सकती है।


90
डबल अंडरस्कोर वाले नामों को विशेष रूप से पायथन द्वारा नियंत्रित किया जाता है; यह सिर्फ एक सम्मेलन नहीं है। देखें docs.python.org/py3k/tutorial/classes.html#private-variables
6502

63
उन्हें अलग तरह से संभाला जाता है, लेकिन यह आपको उन तक पहुंचने से रोकता नहीं है। पुनश्च: ई 30 C0
kindall

4
और क्योंकि "@" अक्षर अजगर कोड में बदसूरत हैं, और dereferencing @decorators स्पेगेटी-कोड की तरह ही भावना देता है।
बेरी त्सकला

18
मैं सहमत नहीं हूँ। स्पेगेटी कोड के समान संरचित कोड कैसे है? अजगर एक सुंदर भाषा है। लेकिन उचित एन्कैप्सुलेशन और संरचित कक्षाओं जैसी सरल चीजों के लिए बेहतर समर्थन के साथ और भी बेहतर होगा।

69
जबकि मैं ज्यादातर मामलों में सहमत हूं, @property डेकोरेटर के पीछे धीमी विधियों को छिपाने के बारे में सावधान रहें। आपके एपीआई के उपयोगकर्ता को उम्मीद है कि संपत्ति का उपयोग वैरिएबल एक्सेस की तरह होता है, और उस अपेक्षा से बहुत दूर भटकना आपके एपीआई को उपयोग करने के लिए अप्रिय बना सकता है।
डिफरेक्स

153

पायथन में आप सिर्फ इसके मज़े के लिए गेटर्स या सेटर या प्रॉपर्टी का इस्तेमाल नहीं करते हैं। आप पहले केवल विशेषताओं का उपयोग करते हैं और फिर बाद में, केवल यदि आवश्यक हो, तो अंततः अपनी कक्षाओं का उपयोग करके कोड को बदलने के बिना किसी संपत्ति में माइग्रेट करें।

वास्तव में एक्सटेंशन .py के साथ बहुत सारे कोड हैं जो गेटर्स और सेटर और इनहेरिटेंस और पॉइंटलेस क्लासेस का उपयोग करते हैं जहां हर जगह जैसे कि एक साधारण टपल होगा, लेकिन यह पायथन का उपयोग करके C ++ या Java में लिखने वाले लोगों से कोड है।

वह पायथन कोड नहीं है।


46
@ 6502, जब आपने कहा "[...] हर जगह व्यर्थ की कक्षाएं, जैसे कि एक साधारण टपल क्या करेगा": एक टपल पर एक वर्ग का लाभ, यह है कि एक वर्ग उदाहरण इसके भागों तक पहुंचने के लिए स्पष्ट नाम प्रदान करता है, जबकि एक टपल नहीं । नाम पठनीयता से बेहतर होते हैं और त्रुटियों से बचते हैं, विशेष रूप से टुपल्स की सदस्यता से, विशेष रूप से तब जब इसे वर्तमान मॉड्यूल के बाहर पारित किया जाना है।
हिबू

15
@ Hibou57: मैं यह नहीं कह रहा कि वर्ग बेकार हैं। लेकिन कभी-कभी एक ट्यूपल पर्याप्त से अधिक होता है। समस्या यह है कि जो जावा या सी ++ से आता है, उसके पास हर चीज के लिए कक्षाएं बनाने के अलावा कोई विकल्प नहीं है, क्योंकि अन्य संभावनाएं उन लेनगेज में उपयोग करने के लिए परेशान हैं। पायथन का उपयोग करने वाले जावा / सी ++ प्रोग्रामिंग का एक और विशिष्ट लक्षण बिना किसी कारण के अमूर्त वर्ग और जटिल वर्ग पदानुक्रम का निर्माण करना है जहां आप केवल पाइक टाइपिंग के लिए स्वतंत्र कक्षाओं के लिए धन्यवाद का उपयोग कर सकते हैं।
६५०२

39
@ Hibou57 कि के लिए यू भी namedtuple उपयोग कर सकते हैं: doughellmann.com/PyMOTW/collections/namedtuple.html
hugo24

5
@JonathonReinhart: यह है 2.6 के बाद से मानक पुस्तकालय में ... देखना docs.python.org/2/library/collections.html
6502

1
जब "अंततः एक संपत्ति की ओर पलायन हो रहा है, तो जरूरत है" यह काफी संभावना है कि आप अपनी कक्षाओं का उपयोग करके ब्रेक कोड करते हैं। गुण अक्सर प्रतिबंधों का परिचय देते हैं - कोई भी कोड, जो इन प्रतिबंधों की उम्मीद नहीं करता था, जैसे ही आप उन्हें लागू करेंगे वे टूट जाएंगे।
याकूब

118

गुणों का उपयोग करने से आप सामान्य विशेषता एक्सेस के साथ शुरू कर सकते हैं और फिर उन्हें गेटर्स के साथ बैक अप कर सकते हैं और बाद में आवश्यकतानुसार बस सकते हैं


3
@GregKrsak यह अजीब लगता है क्योंकि यह है। गुणों को जोड़ने से पहले "सहमति देने वाली वयस्क चीज़" एक अजगर मेमे थी। यह उन लोगों के लिए स्टॉक प्रतिक्रिया थी, जो एक्सेस संशोधक की कमी के बारे में शिकायत करेंगे। जब गुण जोड़े गए थे, तो अचानक एनकैप्सुलेशन वांछनीय हो जाता है। अमूर्त आधार वर्गों के साथ भी यही हुआ। "पायथन हमेशा एनकैप्सुलेशन-ब्रेकिंग के साथ युद्ध में था। स्वतंत्रता गुलामी है। लैम्ब्डा को केवल अपनी लाइन पर फिट होना चाहिए।"
जौनीपील

71

संक्षिप्त उत्तर है: गुण नीचे हाथ जीतता है । हमेशा।

कभी-कभी गेटर्स और सेटर की आवश्यकता होती है, लेकिन फिर भी, मैं उन्हें बाहरी दुनिया में "छिपा" दूँगा। अजगर में यह करने के लिए तरीके (के बहुत सारे हैं getattr, setattr, __getattribute__, आदि ..., लेकिन एक बहुत ही संक्षिप्त और स्वच्छ एक है:

def set_email(self, value):
    if '@' not in value:
        raise Exception("This doesn't look like an email address.")
    self._email = value

def get_email(self):
    return self._email

email = property(get_email, set_email)

यहाँ एक संक्षिप्त लेख है जो पायथन में गेटर्स और बसने के विषय का परिचय देता है।


1
@ बासिकवुल्फ - मुझे लगा कि यह स्पष्ट है कि मैं बाड़ के संपत्ति पक्ष में हूं! :) लेकिन मैं अपने उत्तर को स्पष्ट करने के लिए एक पैरा जोड़ता हूं।
मैक

9
सुझाव: शब्द "हमेशा" एक संकेत है कि लेखक आपको एक तर्क के साथ समझाने का प्रयास कर रहा है, एक तर्क नहीं। तो बोल्डफेस फ़ॉन्ट की उपस्थिति है। (मेरा मतलब है, अगर आप इसके बजाय CAPS देखते हैं, तो - वाह - यह सही होना चाहिए।) देखिए, "संपत्ति" सुविधा जावा (किसी कारण से पायथन के वास्तविक तथ्य) से भिन्न होती है, और इसलिए पायथन के सामुदायिक समूह इसे बेहतर घोषित करता है। वास्तव में, गुण "निहितार्थ से बेहतर है" नियम का उल्लंघन करते हैं, लेकिन कोई भी इसे स्वीकार नहीं करना चाहता है। इसने इसे भाषा में बनाया है, इसलिए अब इसे एक तात्विक तर्क के माध्यम से "पायथोनिक" घोषित किया गया है।
स्टुअर्ट बर्ग

3
कोई भावनाएं आहत नहीं हुईं। :-P मैं केवल यह बताने की कोशिश कर रहा हूं कि इस मामले में "पाइथोनिक" कन्वेंशन असंगत हैं: "स्पष्ट से बेहतर है कि निहितार्थ" का उपयोग करने के साथ सीधे संघर्ष में है property। (यह एक साधारण असाइनमेंट की तरह दिखता है , लेकिन यह एक फ़ंक्शन को कॉल करता है।) इसलिए, "पायथोनिक" अनिवार्य रूप से एक निरर्थक शब्द है, सिवाय तांत्रिक परिभाषा के: "पायथोनिक कन्वेंशन वे चीजें हैं जिन्हें हमने पायथोनिक के रूप में परिभाषित किया है।"
स्टुअर्ट बर्ग

1
अब, एक विषय का पालन करने वाले सम्मेलनों का एक सेट होने का विचार बहुत अच्छा है । यदि इस तरह के सम्मेलनों का एक सेट मौजूद था, तो आप इसे अपनी सोच को निर्देशित करने के लिए स्वयंसिद्धों के एक सेट के रूप में उपयोग कर सकते हैं, न कि केवल याद रखने के लिए ट्रिक्स की एक लंबी चेकलिस्ट, जो काफी कम उपयोगी है। Axioms का उपयोग एक्सट्रपलेशन के लिए किया जा सकता है , और आपको उन समस्याओं से निपटने में मदद करेगा जो अभी तक किसी ने नहीं देखी हैं। यह शर्म की बात है कि propertyफ़ीचर ने पायथोनिक स्वयंसिद्ध विचारों को लगभग व्यर्थ करने के लिए धमकी दी है। तो हम सब छोड़ दिया है एक चेकलिस्ट है।
स्टुअर्ट बर्ग

1
मैं सहमत नहीं हूँ। मैं अधिकांश स्थितियों में गुणों को पसंद करता हूं, लेकिन जब आप इस बात पर जोर देना चाहते हैं कि किसी वस्तु कोself स्थापित करने के अलावा वस्तु को संशोधित करने के अलावा कुछ साइड इफेक्ट्स हैं , तो स्पष्ट सेटर मददगार हो सकते हैं। उदाहरण के लिए, user.email = "..."ऐसा नहीं लगता है कि यह एक अपवाद को बढ़ा सकता है क्योंकि यह सिर्फ एक विशेषता स्थापित करने जैसा दिखता है, जबकि user.set_email("...")यह स्पष्ट करता है कि अपवादों के कोई साइड इफेक्ट हो सकते हैं।
bluenote10

65

[ टीएल? डीआर आप एक कोड उदाहरण के लिए अंत तक छोड़ सकते हैं ।]

मैं वास्तव में एक अलग मुहावरे का उपयोग करना पसंद करता हूं, जो एक बंद के रूप में उपयोग करने के लिए थोड़ा सा शामिल है, लेकिन यदि आपके पास अधिक जटिल उपयोग का मामला है तो अच्छा है।

पहले थोड़ी पृष्ठभूमि।

गुण इसमें उपयोगी हैं कि वे हमें प्रोग्रामेटिक तरीके से सेटिंग और मान दोनों को संभालने की अनुमति देते हैं, लेकिन फिर भी विशेषताओं को विशेषताओं के रूप में एक्सेस करने की अनुमति देते हैं। हम 'हो जाता है' को 'गणना' (अनिवार्य रूप से) में बदल सकते हैं और हम 'सेट' को 'घटनाओं' में बदल सकते हैं। तो मान लें कि हमारे पास निम्न वर्ग है, जिसे मैंने जावा जैसे गेटर्स और सेटर के साथ कोडित किया है।

class Example(object):
    def __init__(self, x=None, y=None):
        self.x = x
        self.y = y

    def getX(self):
        return self.x or self.defaultX()

    def getY(self):
        return self.y or self.defaultY()

    def setX(self, x):
        self.x = x

    def setY(self, y):
        self.y = y

    def defaultX(self):
        return someDefaultComputationForX()

    def defaultY(self):
        return someDefaultComputationForY()

आप सोच रहे होंगे कि मैंने कॉल क्यों नहीं किया defaultXऔर defaultYवस्तु __init__विधि में। कारण यह है कि हमारे मामले में मैं यह मान लेना चाहता हूं कि someDefaultComputationविधियां समय के साथ बदलते मूल्यों को वापस लाती हैं, टाइमस्टैम्प कहती हैं, और जब भी x(या y) सेट नहीं किया जाता है (जहां, इस उदाहरण के उद्देश्य के लिए, "सेट नहीं" का अर्थ है "सेट" कुछ नहीं ") मैं डिफ़ॉल्ट गणना का x's (या y' s) मान चाहता हूं ।

तो यह ऊपर वर्णित कई कारणों के लिए लंगड़ा है। मैं गुणों का उपयोग करके इसे फिर से लिखूंगा:

class Example(object):
    def __init__(self, x=None, y=None):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self.x or self.defaultX()

    @x.setter
    def x(self, value):
        self._x = value

    @property
    def y(self):
        return self.y or self.defaultY()

    @y.setter
    def y(self, value):
        self._y = value

    # default{XY} as before.

हमने क्या हासिल किया है? हमने इन विशेषताओं को विशेषताओं के रूप में संदर्भित करने की क्षमता प्राप्त की है, भले ही दृश्यों के पीछे, हम चल रहे तरीकों को समाप्त करते हैं।

बेशक गुणों की वास्तविक शक्ति यह है कि हम आम तौर पर इन तरीकों को सिर्फ प्राप्त करने और मूल्यों को स्थापित करने के अलावा कुछ करना चाहते हैं (अन्यथा गुणों का उपयोग करने का कोई मतलब नहीं है)। मैंने अपने गेटर उदाहरण में ऐसा किया। जब भी मूल्य निर्धारित नहीं होता है, तो हम मूल रूप से एक फंक्शन बॉडी चला रहे होते हैं। यह एक बहुत ही सामान्य पैटर्न है।

लेकिन हम क्या खो रहे हैं, और हम क्या नहीं कर सकते हैं?

मेरे विचार में, मुख्य झुंझलाहट यह है कि यदि आप एक गटर को परिभाषित करते हैं (जैसा कि हम यहां करते हैं) तो आपको एक सेटर को भी परिभाषित करना होगा। [१] यह अतिरिक्त शोर है जो कोड को बंद कर देता है।

एक और झुंझलाहट यह है कि हमें अभी भी इसमें xऔर yमूल्यों को शुरू करना है __init__। (ठीक है, निश्चित रूप से हम उनका उपयोग करके जोड़ सकते हैं setattr()लेकिन यह अतिरिक्त कोड है।)

तीसरा, जावा जैसे उदाहरण के विपरीत, गेटर्स अन्य मापदंडों को स्वीकार नहीं कर सकते हैं। अब मैं आपको पहले ही यह कहते हुए सुन सकता हूँ, अगर यह पैरामीटर ले रहा है तो यह अच्छा नहीं है! एक आधिकारिक अर्थ में, यह सच है। लेकिन व्यावहारिक अर्थ में, कोई कारण नहीं है कि हम एक नामित विशेषता - जैसे x- और कुछ विशिष्ट मापदंडों के लिए इसके मूल्य को निर्धारित करने में सक्षम नहीं होना चाहिए ।

यह अच्छा होगा अगर हम ऐसा कुछ कर सकते हैं:

e.x[a,b,c] = 10
e.x[d,e,f] = 20

उदाहरण के लिए। निकटतम हम प्राप्त कर सकते हैं कुछ विशेष शब्दार्थों को लागू करने के लिए असाइनमेंट को ओवरराइड करना है:

e.x = [a,b,c,10]
e.x = [d,e,f,30]

और निश्चित रूप से सुनिश्चित करें कि हमारा सेटर जानता है कि पहले तीन मानों को एक शब्दकोश की कुंजी के रूप में कैसे निकाला जाए और इसके मूल्य को एक संख्या या कुछ पर सेट करें।

लेकिन यहां तक ​​कि अगर हमने किया है कि हम अभी भी गुणों के साथ इसका समर्थन नहीं कर सकते हैं, क्योंकि मूल्य प्राप्त करने का कोई तरीका नहीं है क्योंकि हम सभी मापदंडों को प्राप्त करने वाले को पारित नहीं कर सकते हैं। इसलिए हमें एक विषमता का परिचय देते हुए सब कुछ वापस करना पड़ा।

जावा-स्टाइल गेटटर / सेटर हमें इसे संभालने देता है, लेकिन हमें गेट्टर / सेटर की आवश्यकता है।

मेरे मन में जो हम वास्तव में चाहते हैं वह कुछ है जो निम्नलिखित आवश्यकताओं को कैप्चर करता है:

  • उपयोगकर्ता किसी दिए गए विशेषता के लिए केवल एक विधि को परिभाषित करते हैं और वहां संकेत कर सकते हैं कि क्या विशेषता केवल पढ़ने के लिए है या रीड-राइट है। गुण गुणकारी होने पर यह परीक्षण विफल हो जाता है।

  • उपयोगकर्ता को फ़ंक्शन को अंतर्निहित अतिरिक्त चर को परिभाषित करने की कोई आवश्यकता नहीं है, इसलिए हमें कोड में __init__या उसकी आवश्यकता नहीं है setattr। चर सिर्फ इस तथ्य से मौजूद है कि हमने यह नई शैली की विशेषता बनाई है।

  • विशेषता के लिए कोई भी डिफ़ॉल्ट कोड विधि बॉडी में ही निष्पादित होता है।

  • हम विशेषता को एक विशेषता के रूप में सेट कर सकते हैं और इसे एक विशेषता के रूप में संदर्भित कर सकते हैं।

  • हम विशेषता को पैरामीटर कर सकते हैं।

कोड के संदर्भ में, हम लिखने का एक तरीका चाहते हैं:

def x(self, *args):
    return defaultX()

और फिर कर सकेंगे:

print e.x     -> The default at time T0
e.x = 1
print e.x     -> 1
e.x = None
print e.x     -> The default at time T1

इत्यादि।

हम एक पैरामीटर योग्य विशेषता के विशेष मामले के लिए ऐसा करने का एक तरीका भी चाहते हैं, लेकिन फिर भी डिफ़ॉल्ट असाइन केस को काम करने की अनुमति देते हैं। आप देखेंगे कि मैंने इससे कैसे निपटा।

अब टू द पॉइंट (या! द पॉइंट!)। इसके लिए मैं जो समाधान लेकर आया, वह इस प्रकार है।

हम एक संपत्ति की धारणा को बदलने के लिए एक नई वस्तु बनाते हैं। ऑब्जेक्ट का उद्देश्य इसके लिए सेट किए गए वैरिएबल के मूल्य को संग्रहीत करना है, लेकिन यह कोड पर एक हैंडल भी रखता है जो जानता है कि डिफ़ॉल्ट की गणना कैसे करें। इसका काम सेट को स्टोर करना है valueया methodअगर उस मूल्य को सेट नहीं करना है तो उसे चलाना है ।

चलो इसे ए कहते हैं UberProperty

class UberProperty(object):

    def __init__(self, method):
        self.method = method
        self.value = None
        self.isSet = False

    def setValue(self, value):
        self.value = value
        self.isSet = True

    def clearValue(self):
        self.value = None
        self.isSet = False

मेरा मानना methodहै कि एक वर्ग विधि है, valueका मान है UberProperty, और मैंने जोड़ा है isSetक्योंकि Noneएक वास्तविक मूल्य हो सकता है और यह हमें एक साफ तरीका बताता है कि वास्तव में "कोई मूल्य नहीं" है। एक और तरीका किसी प्रकार का प्रहरी है।

यह मूल रूप से हमें एक वस्तु देता है जो हम जो चाहते हैं वह कर सकते हैं, लेकिन हम वास्तव में इसे अपनी कक्षा में कैसे डालते हैं? खैर, गुण सज्जाकारों का उपयोग करते हैं; हम क्यों नहीं? आइए देखें कि यह कैसा दिख सकता है (यहां से मैं सिर्फ एक 'विशेषता' का उपयोग करने के लिए छड़ी जा रहा हूं, x)।

class Example(object):

    @uberProperty
    def x(self):
        return defaultX()

यह वास्तव में अभी तक निश्चित रूप से काम नहीं करता है। हमें इसे लागू करना uberPropertyऔर सुनिश्चित करना है कि यह प्राप्त और सेट दोनों को संभालता है।

चलो के साथ शुरू करते हैं।

मेरा पहला प्रयास बस एक नई UberProperty ऑब्जेक्ट बनाना और उसे वापस करना था:

def uberProperty(f):
    return UberProperty(f)

मुझे जल्दी से पता चला, निश्चित रूप से, कि यह काम नहीं करता है: पायथन कभी भी कॉल करने योग्य वस्तु को बांधता नहीं है और मुझे फ़ंक्शन को कॉल करने के लिए ऑब्जेक्ट की आवश्यकता होती है। कक्षा में डेकोरेटर बनाने से भी काम नहीं चलता, क्योंकि अब हमारे पास क्लास है, फिर भी हमारे पास काम करने के लिए कोई वस्तु नहीं है।

तो हम यहाँ और अधिक करने में सक्षम होने की जरूरत है। हम जानते हैं कि एक विधि को केवल एक समय का प्रतिनिधित्व करने की आवश्यकता है, इसलिए चलो आगे बढ़ें और हमारे डेकोरेटर को रखें, लेकिन UberPropertyकेवल methodसंदर्भ को संग्रहीत करने के लिए संशोधित करें :

class UberProperty(object):

    def __init__(self, method):
        self.method = method

यह कॉल करने योग्य भी नहीं है, इसलिए फिलहाल कुछ भी काम नहीं कर रहा है।

हम तस्वीर को कैसे पूरा करते हैं? जब हम अपने नए डेकोरेटर का उपयोग करके उदाहरण वर्ग बनाते हैं, तो हम क्या करते हैं:

class Example(object):

    @uberProperty
    def x(self):
        return defaultX()

print Example.x     <__main__.UberProperty object at 0x10e1fb8d0>
print Example().x   <__main__.UberProperty object at 0x10e1fb8d0>

दोनों ही मामलों में हम वापस आ जाते हैं UberPropertyजो निश्चित रूप से एक कॉल करने योग्य नहीं है, इसलिए यह बहुत काम का नहीं है।

जिस चीज की हमें जरूरत है UberProperty, उसे डेकोरेटर द्वारा बनाए गए इंस्टेंस को क्लास में किसी ऑब्जेक्ट के लिए बनाए जाने के बाद डायनामिक तरीके से बांधने का कुछ तरीका है , इससे पहले कि यूजर्स को उस यूजर को यूज के लिए वापस कर दिया गया है। उम, हाँ, यह एक __init__कॉल है, यार।

आइए लिखते हैं कि हम क्या चाहते हैं कि हमारा परिणाम पहले मिले। हम UberPropertyएक उदाहरण के लिए बाध्य कर रहे हैं , इसलिए लौटने के लिए एक स्पष्ट बात एक बाउंडअपप्रोपरेटी होगी। यह वह जगह है जहाँ हम वास्तव में xविशेषता के लिए स्थिति बनाए रखेंगे ।

class BoundUberProperty(object):
    def __init__(self, obj, uberProperty):
        self.obj = obj
        self.uberProperty = uberProperty
        self.isSet = False

    def setValue(self, value):
        self.value = value
        self.isSet = True

    def getValue(self):
        return self.value if self.isSet else self.uberProperty.method(self.obj)

    def clearValue(self):
        del self.value
        self.isSet = False

अब हम प्रतिनिधित्व करते हैं; किसी वस्तु पर ये कैसे प्राप्त होते हैं? कुछ दृष्टिकोण हैं, लेकिन सबसे आसान यह समझाने __init__के लिए कि मानचित्रण करने के लिए विधि का उपयोग करता है । जब तक __init__हमारे डेकोरेटर चलाए जाते हैं तब तक कहा जाता है, इसलिए केवल ऑब्जेक्ट के माध्यम से देखने __dict__और किसी भी विशेषता को अपडेट करने की आवश्यकता है जहां विशेषता का मूल्य प्रकार का है UberProperty

अब, उबेर-गुण शांत हैं और हम शायद उन्हें बहुत उपयोग करना चाहते हैं, इसलिए यह सिर्फ एक आधार वर्ग बनाने के लिए समझ में आता है जो सभी उपवर्गों के लिए ऐसा करता है। मुझे लगता है कि आप जानते हैं कि बेस क्लास को क्या कहा जाने वाला है।

class UberObject(object):
    def __init__(self):
        for k in dir(self):
            v = getattr(self, k)
            if isinstance(v, UberProperty):
                v = BoundUberProperty(self, v)
                setattr(self, k, v)

हम इसे जोड़ते हैं, हमारे उदाहरण को इनहेरिट से बदलते हैं UberObject, और ...

e = Example()
print e.x               -> <__main__.BoundUberProperty object at 0x104604c90>

संशोधित होने के बाद x:

@uberProperty
def x(self):
    return *datetime.datetime.now()*

हम एक साधारण परीक्षण चला सकते हैं:

print e.x.getValue()
print e.x.getValue()
e.x.setValue(datetime.date(2013, 5, 31))
print e.x.getValue()
e.x.clearValue()
print e.x.getValue()

और हमें वह आउटपुट मिलता है जो हम चाहते थे:

2013-05-31 00:05:13.985813
2013-05-31 00:05:13.986290
2013-05-31
2013-05-31 00:05:13.986310

(जी, मैं देर से काम कर रहा हूं।)

ध्यान दें कि मैं का इस्तेमाल किया है getValue, setValueऔर clearValueयहाँ। इसका कारण यह है कि मैंने अभी तक इन्हें स्वचालित रूप से वापस लाने के साधनों में लिंक नहीं किया है।

लेकिन मुझे लगता है कि यह अब के लिए रुकने के लिए एक अच्छी जगह है, क्योंकि मैं थक गया हूं। आप यह भी देख सकते हैं कि जो मुख्य कार्यक्षमता हम चाहते थे, वह जगह पर है; बाकी विंडो ड्रेसिंग है। महत्वपूर्ण प्रयोज्यता विंडो ड्रेसिंग, लेकिन वह तब तक प्रतीक्षा कर सकती है जब तक कि मेरे पास पोस्ट को अपडेट करने के लिए कोई बदलाव न हो।

मैं इन बातों को संबोधित करके अगली पोस्टिंग में उदाहरण समाप्त करूँगा:

  • हमें यह सुनिश्चित करने की आवश्यकता है कि UberObject's __init__को हमेशा उपवर्गों द्वारा बुलाया जाता है।

    • इसलिए हम या तो इसे कहीं बुलाते हैं या हम इसे लागू होने से रोकते हैं।
    • हम देखेंगे कि मेटाक्लास के साथ यह कैसे किया जाता है।
  • हमें यह सुनिश्चित करने की ज़रूरत है कि हम उस सामान्य मामले को संभालें जहाँ कोई 'उपनाम' किसी अन्य चीज़ के लिए कार्य करता है, जैसे:

      class Example(object):
          @uberProperty
          def x(self):
              ...
    
          y = x
  • हमें डिफ़ॉल्ट रूप e.xसे वापस लौटने की आवश्यकता है e.x.getValue()

    • जो हम वास्तव में देखेंगे वह यह है कि यह एक ऐसा क्षेत्र है जहां मॉडल विफल हो जाता है।
    • यह पता चला है कि मूल्य प्राप्त करने के लिए हमें हमेशा फ़ंक्शन कॉल का उपयोग करना होगा।
    • लेकिन हम इसे एक नियमित फ़ंक्शन कॉल की तरह बना सकते हैं और उपयोग करने से बच सकते हैं e.x.getValue()। (ऐसा करना स्पष्ट है, यदि आपने इसे पहले से तय नहीं किया है।)
  • हमें सेटिंग का समर्थन करने की आवश्यकता है e.x directly, जैसे कि e.x = <newvalue>। हम इसे मूल श्रेणी में भी कर सकते हैं, लेकिन हमें इसे __init__संभालने के लिए अपना कोड अपडेट करना होगा।

  • अंत में, हम पैरामीटरयुक्त विशेषताएँ जोड़ेंगे। यह बहुत स्पष्ट होना चाहिए कि हम ऐसा कैसे करेंगे।

यहाँ कोड है क्योंकि यह अब तक मौजूद है:

import datetime

class UberObject(object):
    def uberSetter(self, value):
        print 'setting'

    def uberGetter(self):
        return self

    def __init__(self):
        for k in dir(self):
            v = getattr(self, k)
            if isinstance(v, UberProperty):
                v = BoundUberProperty(self, v)
                setattr(self, k, v)


class UberProperty(object):
    def __init__(self, method):
        self.method = method

class BoundUberProperty(object):
    def __init__(self, obj, uberProperty):
        self.obj = obj
        self.uberProperty = uberProperty
        self.isSet = False

    def setValue(self, value):
        self.value = value
        self.isSet = True

    def getValue(self):
        return self.value if self.isSet else self.uberProperty.method(self.obj)

    def clearValue(self):
        del self.value
        self.isSet = False

    def uberProperty(f):
        return UberProperty(f)

class Example(UberObject):

    @uberProperty
    def x(self):
        return datetime.datetime.now()

[१] मैं इस मामले में अभी भी पीछे रह सकता हूँ।


53
हाँ, यह 'tldr' है। क्या आप कृपया संक्षेप में बता सकते हैं कि आप यहाँ क्या करने की कोशिश कर रहे हैं?
पूलि

9
@ एडम return self.x or self.defaultX()यह खतरनाक कोड है। क्या होता है जब self.x == 0?
केली थॉमस

FYI करें, आप इसे बना सकते हैं ताकि आप प्राप्त करने वाले के प्रकार को माप सकें। इसमें चर को एक कस्टम वर्ग बनाना शामिल होगा, जिसमें से आपने __getitem__विधि को ओवरराइड कर दिया है । हालांकि यह अजीब होगा, क्योंकि तब आपके पास पूरी तरह से गैर मानक पायथन होगा।
होगा

2
@KellyThomas उदाहरण को सरल रखने की कोशिश कर रहा है। इसे सही तरीके से करने के लिए आपको पूरी तरह से x तानाशाह प्रविष्टि बनाने और हटाने की आवश्यकता होगी , क्योंकि कोई भी मान विशेष रूप से सेट नहीं किया गया हो सकता है। लेकिन हां, आप बिल्कुल सही हैं कि यह कुछ ऐसा है जिसे आपको उत्पादन उपयोग के मामले में विचार करना होगा।
एडम डोनह्यू

जावा-जैसे गेटर्स आपको समान गणना करने की अनुमति देते हैं, न?
प्रात:

26

मुझे लगता है कि दोनों का अपना स्थान है। उपयोग के साथ एक मुद्दा@property यह है कि मानक कक्षा तंत्रों का उपयोग करके उपवर्गों में गेटर्स या बसने वालों के व्यवहार का विस्तार करना कठिन है। समस्या यह है कि संपत्ति में वास्तविक गेट्टर / सेटर फ़ंक्शन छिपे हुए हैं।

आप वास्तव में कार्यों को पकड़ सकते हैं, जैसे कि

class C(object):
    _p = 1
    @property
    def p(self):
        return self._p
    @p.setter
    def p(self, val):
        self._p = val

आप गेट्टर और सेटर फ़ंक्शंस को एक्सेस कर सकते हैं C.p.fgetऔर C.p.fset, लेकिन आप उन्हें बढ़ाने के लिए सामान्य विधि वंशानुक्रम (जैसे सुपर) सुविधाओं का उपयोग आसानी से नहीं कर सकते हैं। सुपर की पेचीदगियों में कुछ खुदाई के बाद, आप वास्तव में इस तरह से सुपर का उपयोग कर सकते हैं :

# Using super():
class D(C):
    # Cannot use super(D,D) here to define the property
    # since D is not yet defined in this scope.
    @property
    def p(self):
        return super(D,D).p.fget(self)

    @p.setter
    def p(self, val):
        print 'Implement extra functionality here for D'
        super(D,D).p.fset(self, val)

# Using a direct reference to C
class E(C):
    p = C.p

    @p.setter
    def p(self, val):
        print 'Implement extra functionality here for E'
        C.p.fset(self, val)

सुपर () का उपयोग करना, हालांकि, काफी क्लंकी है, क्योंकि संपत्ति को फिर से परिभाषित किया जाना है, और आपको पी की एक अनबाउंड कॉपी प्राप्त करने के लिए थोड़े काउंटर-सहज सुपर (क्ल्स, क्ल्स) तंत्र का उपयोग करना होगा।


20

गुणों का उपयोग करना मेरे लिए अधिक सहज है और अधिकांश कोड में बेहतर है।

की तुलना

o.x = 5
ox = o.x

बनाम

o.setX(5)
ox = o.getX()

मेरे लिए काफी स्पष्ट है जिसे पढ़ना आसान है। इसके अलावा गुण निजी चर के लिए बहुत आसान अनुमति देता है।


12

मैं ज्यादातर मामलों में न तो उपयोग करना पसंद करूंगा। गुणों के साथ समस्या यह है कि वे कक्षा को कम पारदर्शी बनाते हैं। विशेष रूप से, यह एक मुद्दा है यदि आप एक सेटर से अपवाद उठाना चाहते थे। उदाहरण के लिए, यदि आपके पास Account.email प्रॉपर्टी है:

class Account(object):
    @property
    def email(self):
        return self._email

    @email.setter
    def email(self, value):
        if '@' not in value:
            raise ValueError('Invalid email address.')
        self._email = value

तब वर्ग का उपयोगकर्ता यह उम्मीद नहीं करता है कि संपत्ति के लिए एक मूल्य प्रदान करना अपवाद का कारण बन सकता है:

a = Account()
a.email = 'badaddress'
--> ValueError: Invalid email address.

नतीजतन, अपवाद अखंडित हो सकता है, और या तो कॉल श्रृंखला में बहुत अधिक प्रचारित किया जा सकता है ठीक से संभाला जा सकता है, या प्रोग्राम उपयोगकर्ता को प्रस्तुत किए जा रहे एक बहुत ही बेकार ट्रेसबैक में (जो कि अजगर और जावा की दुनिया में बहुत आम है) )।

मैं गेटर्स और सेटर का उपयोग करने से भी बचूंगा:

  • क्योंकि अग्रिम में सभी गुणों के लिए उन्हें परिभाषित करने में बहुत समय लगता है,
  • कोड की मात्रा को अनावश्यक रूप से लंबा बनाता है, जिससे कोड को समझना और बनाए रखना अधिक कठिन होता है,
  • यदि आप उन्हें केवल आवश्यकतानुसार गुणों के लिए परिभाषित करते हैं, तो कक्षा का इंटरफ़ेस बदल जाएगा, जिससे कक्षा के सभी उपयोगकर्ता आहत होंगे

गुणों और गेटर्स / सेटर्स के बजाय मैं अच्छी तरह से परिभाषित स्थानों में जटिल तर्क करना पसंद करता हूं जैसे कि सत्यापन विधि:

class Account(object):
    ...
    def validate(self):
        if '@' not in self.email:
            raise ValueError('Invalid email address.')

या एक परिचित खाता.समर्थन विधि।

ध्यान दें कि मैं यह कहने की कोशिश नहीं कर रहा हूं कि ऐसे मामले नहीं हैं जब गुण उपयोगी होते हैं, केवल यह कि आप बेहतर हो सकते हैं यदि आप अपनी कक्षाओं को सरल और पारदर्शी बना सकते हैं जो आपको उनकी आवश्यकता नहीं है।


3
@ user2239734 मुझे लगता है कि आप गुणों की अवधारणा को गलत समझते हैं। यद्यपि आप संपत्ति सेट करते समय मूल्य को मान्य कर सकते हैं, लेकिन ऐसा करने की कोई आवश्यकता नहीं है। आपके पास validate()एक वर्ग में गुण और एक विधि दोनों हो सकते हैं । एक संपत्ति का उपयोग केवल तब किया जाता है जब आपके पास एक साधारण obj.x = yअसाइनमेंट के पीछे एक जटिल तर्क होता है, और यह है कि तर्क क्या है।
ज़ौर नसीबोव

12

मुझे लगता है कि संपत्तियां आपको लिखने वाले के ओवरहेड प्राप्त करने देती हैं और केवल तब ही बसाती हैं जब आपको वास्तव में उनकी आवश्यकता होती है।

जावा प्रोग्रामिंग संस्कृति दृढ़ता से गुणों को कभी भी उपयोग न करने की सलाह देती है, और इसके बजाय, गेटर्स और सेटरों के माध्यम से जाते हैं, और केवल उन लोगों की आवश्यकता होती है जो वास्तव में आवश्यक हैं। यह कोड के इन स्पष्ट टुकड़ों को हमेशा लिखने की क्रिया है, और ध्यान दें कि 70% समय उन्हें कभी भी कुछ गैर-तुच्छ तर्क द्वारा प्रतिस्थापित नहीं किया जाता है।

पायथन में, लोग वास्तव में उस तरह के ओवरहेड की देखभाल करते हैं, ताकि आप निम्नलिखित अभ्यास को अपना सकें:

  • जब जरूरत न हो तो पहले गेटर्स और सेटर का इस्तेमाल न करें
  • @propertyअपने बाकी कोड के सिंटैक्स को बदले बिना उन्हें लागू करने के लिए उपयोग करें ।

1
"और ध्यान दें कि 70% समय वे कभी भी कुछ गैर-तुच्छ तर्क से प्रतिस्थापित नहीं होते हैं।" - यह एक विशिष्ट संख्या है, क्या यह कहीं से आ रहा है, या आप इसे एक विशाल "प्रचंड बहुमत" थोड़े बात के रूप में प्रस्तुत कर रहे हैं (मैं स्पष्ट नहीं हो रहा हूं, अगर कोई अध्ययन है जो उस संख्या को निर्धारित करता है, तो मैं होगा। वास्तव में इसे पढ़ने में दिलचस्पी)
एडम पार्किं

1
ओह नो सॉरी। ऐसा लगता है कि इस नंबर का बैकअप लेने के लिए मेरे पास कुछ अध्ययन है, लेकिन मेरा मतलब केवल "अधिकांश समय" के रूप में था।
फुलिमोटन

7
यह नहीं है कि लोग ओवरहेड के बारे में परवाह करते हैं, यह है कि पायथन में आप क्लाइंट कोड को बदलने के बिना डायरेक्ट एक्सेस से एक्सेसर विधियों में बदल सकते हैं, इसलिए आपके पास सीधे पहले गुणों को उजागर करके खोने के लिए कुछ भी नहीं है।
नील जी

10

मुझे आश्चर्य है कि किसी ने यह उल्लेख नहीं किया है कि संपत्तियां एक वर्णनात्मक वर्ग की बाध्य विधियां हैं, एडम डोनोह्यू और नीलमेनमैरिस अपने पदों में बिल्कुल इस विचार को प्राप्त करते हैं - कि गेटर्स और सेटर फ़ंक्शन हैं और इसका उपयोग किया जा सकता है:

  • सत्यापित करें
  • डेटा में परिवर्तन
  • बत्तख प्रकार (दूसरे प्रकार के लिए मोटे प्रकार)

यह कार्यान्वयन विवरण और कोड क्रूफ को छिपाने के लिए एक स्मार्ट तरीका प्रस्तुत करता है जैसे कि नियमित अभिव्यक्ति, टाइप कास्ट, कोशिश .. ब्लॉक, अभिकथन या गणना मूल्यों को छोड़कर।

सामान्य तौर पर किसी वस्तु पर CRUD अक्सर काफी सांसारिक हो सकता है लेकिन डेटा के उदाहरण पर विचार करें जो एक संबंधपरक डेटाबेस के लिए जारी रहेगा। ओआरएम किसी संपत्ति वर्ग में परिभाषित विशेष एसक्यूएल वर्नाक्यूलर के कार्यान्वयन के विवरणों को छिपा सकते हैं, संपत्ति वर्ग में परिभाषित fdel जो भयानक का प्रबंधन करेगा अगर .. elif .. और सीढ़ी जो OO कोड में इतनी बदसूरत हैं - सरल और उजागर करना ORM का उपयोग करself.variable = something डेवलपर के लिए विवरणों को सुरुचिपूर्ण और संक्षिप्त करें ।

यदि कोई केवल एक बंधन और अनुशासन भाषा (यानी जावा) के कुछ अस्पष्ट रूप में गुणों के बारे में सोचता है, तो वे वर्णनकर्ताओं के बिंदु को याद कर रहे हैं।


6

जटिल परियोजनाओं में मैं स्पष्ट सेटर फ़ंक्शन के साथ रीड-ओनली गुण (या गेटर्स) का उपयोग करना पसंद करता हूं:

class MyClass(object):
...        
@property
def my_attr(self):
    ...

def set_my_attr(self, value):
    ...

लंबे समय तक रहने वाली परियोजनाओं में डिबगिंग और रिफैक्टरिंग को कोड लिखने से अधिक समय लगता है। उपयोग करने के लिए कई डाउनसाइड हैं @property.setterजो डिबगिंग को और भी कठिन बनाता है:

1) अजगर किसी मौजूदा वस्तु के लिए नई विशेषताएँ बनाने की अनुमति देता है। यह ट्रैक करने के लिए निम्नलिखित गलतफ़हमी बनाता है:

my_object.my_atttr = 4.

यदि आपकी वस्तु एक जटिल एल्गोरिथ्म है, तो आप यह पता लगाने की कोशिश में काफी समय बिताएंगे कि यह क्यों नहीं जुटता है (ऊपर की पंक्ति में एक अतिरिक्त 'टी' देखें)

2) सेटर कभी-कभी एक जटिल और धीमी गति से विकसित हो सकता है (जैसे डेटाबेस को मारना)। किसी अन्य डेवलपर के लिए यह पता लगाना काफी कठिन होगा कि निम्न फ़ंक्शन बहुत धीमा क्यों है। वह प्रोफाइलिंग do_something()विधि पर बहुत समय बिता सकता है , जबकि my_object.my_attr = 4.वास्तव में मंदी का कारण है:

def slow_function(my_object):
    my_object.my_attr = 4.
    my_object.do_something()

5

दोनों @propertyऔर पारंपरिक गेटर्स और सेटर्स के अपने फायदे हैं। यह आपके उपयोग के मामले पर निर्भर करता है।

के लाभ @property

  • डेटा एक्सेस के कार्यान्वयन को बदलते समय आपको इंटरफ़ेस बदलना नहीं पड़ता है। जब आपका प्रोजेक्ट छोटा होता है, तो आप शायद क्लास मेंबर तक पहुँचने के लिए डायरेक्ट एट्रीब्यूट एक्सेस का उपयोग करना चाहते हैं। उदाहरण के लिए, मान लें कि आपके पास एक fooप्रकार की वस्तु है Foo, जिसमें एक सदस्य है num। तो आप बस के साथ इस सदस्य को प्राप्त कर सकते हैं num = foo.num। जैसे-जैसे आपकी परियोजना बढ़ती है, आपको ऐसा महसूस हो सकता है कि साधारण विशेषता के उपयोग पर कुछ चेक या डिबग की आवश्यकता है। तब आप कक्षा के @property भीतर ऐसा कर सकते हैं । डेटा एक्सेस इंटरफ़ेस समान रहता है ताकि क्लाइंट कोड को संशोधित करने की आवश्यकता न हो।

    PEP-8 से उद्धृत :

    सरल सार्वजनिक डेटा विशेषताओं के लिए, जटिल अभिगमक / उत्परिवर्ती विधियों के बिना, केवल विशेषता नाम को उजागर करना सबसे अच्छा है। ध्यान रखें कि पायथन भविष्य में वृद्धि के लिए एक आसान मार्ग प्रदान करता है, तो क्या आपको पता होना चाहिए कि एक साधारण डेटा विशेषता को कार्यात्मक व्यवहार बढ़ने की आवश्यकता है। उस स्थिति में, सरल डेटा विशेषता एक्सेस सिंटैक्स के पीछे कार्यात्मक कार्यान्वयन को छिपाने के लिए गुणों का उपयोग करें।

  • का उपयोग करते हुए @propertyअजगर में डेटा का उपयोग के रूप में माना जाता है के लिए pythonic :

    • यह पायथन (जावा नहीं) प्रोग्रामर के रूप में आपकी आत्म-पहचान को मजबूत कर सकता है।

    • यदि आपका साक्षात्कारकर्ता जावा-शैली के गेटर्स और बसने वाले विरोधी पैटर्न के बारे में सोचता है तो यह आपकी नौकरी के साक्षात्कार में मदद कर सकता है ।

पारंपरिक गेटर्स और सेटर के लाभ

  • पारंपरिक गेटर्स और सेटर सरल विशेषता एक्सेस की तुलना में अधिक जटिल डेटा एक्सेस की अनुमति देते हैं। उदाहरण के लिए, जब आप एक वर्ग के सदस्य को सेट कर रहे होते हैं, तो कभी-कभी आपको एक ध्वज की आवश्यकता होती है, जहां आपको संकेत मिलता है कि आप इस ऑपरेशन को बाध्य करना चाहते हैं, भले ही कुछ सही न लगे। हालांकि यह स्पष्ट नहीं है कि प्रत्यक्ष सदस्य पहुंच को कैसे बढ़ाया जाए foo.num = num, आप अपने पारंपरिक सेटर को अतिरिक्त forceपैरामीटर के साथ आसानी से बढ़ा सकते हैं :

    def Foo:
        def set_num(self, num, force=False):
            ...
  • पारंपरिक गेटर्स और सेटर यह स्पष्ट करते हैं कि एक क्लास मेंबर एक्सेस एक विधि से होता है। इसका मतलब है की:

    • परिणाम के रूप में आपको जो मिलता है, वही नहीं हो सकता है, जो उस वर्ग के भीतर जमा होता है।

    • यहां तक ​​कि अगर पहुंच एक साधारण विशेषता पहुंच की तरह दिखती है, तो प्रदर्शन इससे बहुत भिन्न हो सकता है।

    जब तक आपके वर्ग के उपयोगकर्ता @propertyहर विशेषता एक्सेस स्टेटमेंट के पीछे छिपने की उम्मीद करते हैं, तब तक ऐसी चीजें स्पष्ट करना आपके वर्ग उपयोगकर्ताओं को आश्चर्यचकित करने में मदद कर सकता है।

  • जैसा कि @NeilenMarais और इस पोस्ट में उल्लेख किया गया है , उपवर्गों में पारंपरिक गेटर्स और बसने का विस्तार करना प्रॉपर्टीज की तुलना में आसान है।

  • पारंपरिक गेटर्स और सेटर्स का लंबे समय से विभिन्न भाषाओं में व्यापक रूप से उपयोग किया जाता रहा है। यदि आपकी टीम में विभिन्न पृष्ठभूमि के लोग हैं, तो वे अधिक परिचित हैं @property। इसके अलावा, जैसा कि आपकी परियोजना बढ़ती है, अगर आपको पायथन से दूसरी भाषा में प्रवास करने की आवश्यकता हो सकती है @property, जो पारंपरिक गेटर्स और सेटर का उपयोग करके माइग्रेशन को सुचारू बना देगा।

चेतावनियां

  • न तो @propertyऔर न ही पारंपरिक गेटर्स और सेटर वर्ग के सदस्य को निजी बनाते हैं, भले ही आप उसके नाम से पहले डबल अंडरस्कोर का उपयोग करें:

    class Foo:
        def __init__(self):
            self.__num = 0
    
        @property
        def num(self):
            return self.__num
    
        @num.setter
        def num(self, num):
            self.__num = num
    
        def get_num(self):
            return self.__num
    
        def set_num(self, num):
            self.__num = num
    
    foo = Foo()
    print(foo.num)          # output: 0
    print(foo.get_num())    # output: 0
    print(foo._Foo__num)    # output: 0

2

यहाँ "प्रभावी अजगर: बेहतर पायथन को लिखने के 90 विशिष्ट तरीके" (कमाल की किताब है। मैं आपको इसकी सलाह देता हूं) से कुछ अंश प्रस्तुत करता हूं।

याद रखने वाली चीज़ें

Attributes सरल सार्वजनिक विशेषताओं का उपयोग करके नए वर्ग इंटरफेस को परिभाषित करें और सेटर और गेट्टर विधियों को परिभाषित करने से बचें।

If यदि आवश्यक हो, तो आपकी वस्तुओं पर विशेषताओं तक पहुंचने के लिए विशेष व्यवहार को परिभाषित करने के लिए @property का उपयोग करें।

Per कम से कम आश्चर्य के नियम का पालन करें और अपने @property तरीकों में विषम दुष्प्रभावों से बचें।

@ सुनिश्चित करें कि @property विधियां तेज हैं; धीमे या जटिल काम के लिए — विशेष रूप से I / O को शामिल करने या इसके साइड इफेक्ट के कारण - इसके बजाय सामान्य तरीकों का उपयोग करें।

@Property का एक उन्नत लेकिन सामान्य उपयोग संक्रमण है जो एक बार एक साधारण संख्यात्मक विशेषता पर एक-पर-फ्लाई गणना में बदल रहा था। यह अत्यंत उपयोगी है क्योंकि यह आपको किसी भी कॉल साइट को फिर से लिखे जाने की आवश्यकता के बिना एक वर्ग के सभी मौजूदा उपयोग को स्थानांतरित करने की अनुमति देता है (जो कि कॉलिंग कोड जिसे आप नियंत्रित नहीं करते हैं, विशेष रूप से महत्वपूर्ण है)। @property समय के साथ इंटरफेस में सुधार के लिए एक महत्वपूर्ण स्टॉपगैप भी प्रदान करता है।

मुझे विशेष रूप से @property पसंद है क्योंकि यह आपको समय के साथ एक बेहतर डेटा मॉडल की ओर वृद्धिशील प्रगति करने देता है।
@property आपको वास्तविक दुनिया कोड में आने वाली समस्याओं के समाधान में मदद करने के लिए एक उपकरण है। इसका अधिक उपयोग न करें। जब आप अपने आप को बार-बार @property विधियों का विस्तार करते हुए पाते हैं, तो संभवतः यह आपके कोड के खराब डिज़ाइन पर फ़र्श करने के बजाय अपनी कक्षा को फिर से भरने का समय है।

Attributes मौजूदा उदाहरण देने के लिए @property का प्रयोग नई कार्यक्षमता को दर्शाता है।

Ty @property का उपयोग करके बेहतर डेटा मॉडल की ओर वृद्धिशील प्रगति करें।

Per जब आप अपने आप को बहुत अधिक जोर से इस्तेमाल कर पाते हैं तो एक वर्ग और सभी कॉल साइटों को फिर से शुरू करने पर विचार करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.