अजगर में संपत्ति की सुविधा का उपयोग करने के बारे में वास्तविक दुनिया उदाहरण?


142

मुझे इस बात में दिलचस्पी है कि @propertyपायथन में कैसे उपयोग किया जाए। मैंने अजगर डॉक्स और उदाहरण को पढ़ा है, मेरी राय में, सिर्फ एक खिलौना कोड है:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

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

    @x.deleter
    def x(self):
        del self._x

मुझे नहीं पता कि _xसंपत्ति डेकोरेटर के साथ भराई लपेटने से मुझे क्या लाभ हो सकता है । क्यों नहीं लागू के रूप में:

class C(object):
    def __init__(self):
        self.x = None

मुझे लगता है, संपत्ति की स्थिति कुछ स्थितियों में उपयोगी हो सकती है। लेकिन जब? क्या कोई मुझे कुछ वास्तविक दुनिया के उदाहरण दे सकता है?

धन्यवाद।


9
संपत्ति सज्जाकार [यहाँ क्लिक करें ] के बारे में यह सबसे अच्छा और साफ-सुथरा विवरण है
सुमुदु

2
@ आपके द्वारा प्रदान किए गए लिंक में अंतिम उदाहरण में, c = C सेल्सियस (-500) सेट करने से कोई भी वैल्यूएयर नहीं गिरती, जो मुझे लगता है कि अपेक्षित परिणाम प्राप्त नहीं कर रहा है।
सजुक

@Anubis से सहमत हैं। इसे यहां सही तरीके से लागू किया गया है: python-course.eu/python3_properties.php
anon01

जवाबों:


91

अन्य उदाहरण सेट विशेषताओं का सत्यापन / फ़िल्टरिंग होगा (उन्हें सीमा या स्वीकार्य होने के लिए मजबूर करना) और जटिल या तेजी से बदलते शब्दों का आलसी मूल्यांकन।

एक विशेषता के पीछे छिपी जटिल गणना:

class PDB_Calculator(object):
    ...
    @property
    def protein_folding_angle(self):
        # number crunching, remote server calls, etc
        # all results in an angle set in 'some_angle'
        # It could also reference a cache, remote or otherwise,
        # that holds the latest value for this angle
        return some_angle

>>> f = PDB_Calculator()
>>> angle = f.protein_folding_angle
>>> angle
44.33276

मान्यता:

class Pedometer(object)
    ...
    @property
    def stride_length(self):
        return self._stride_length

    @stride_length.setter
    def stride_length(self, value):
        if value > 10:
            raise ValueError("This pedometer is based on the human stride - a stride length above 10m is not supported")
        else:
            self._stride_length = value

1
मुझे PDB_Calculator उदाहरण पसंद है - जटिल चीजें दूर हैं, पूरी बात काम करती है और उपयोगकर्ता सादगी का आनंद ले सकता है!
एडम कुर्कविज़

2
संभवतः, समर्थक दृष्टिकोण से, ये बहुत अच्छे उदाहरण हैं। लेकिन, एक noobie के रूप में, मुझे यह उदाहरण काफी अप्रभावी लगता है। मेरा बुरा ...:
किमी। किमी

77

एक साधारण उपयोग का मामला एक रीड ओनली एट्रिब्यूट सेट करने के लिए होगा, जैसा कि आप जानते हैं कि _xअजगर में एक अंडरस्कोर के साथ एक वेरिएबल नाम होता है आमतौर पर इसका मतलब है कि यह निजी (आंतरिक उपयोग) है, लेकिन कभी-कभी हम इंस्टेंस विशेषता को पढ़ने में सक्षम होना चाहते हैं और लिखना नहीं चाहते हैं। इसलिए हम इसके propertyलिए उपयोग कर सकते हैं :

>>> class C(object):

        def __init__(self, x):
            self._x = x

        @property
        def x(self):
            return self._x

>>> c = C(1)
>>> c.x
1
>>> c.x = 2
AttributeError        Traceback (most recent call last)

AttributeError: can't set attribute

6
c._xयदि उपयोगकर्ता चाहे तो एक सेट कर सकता है। पायथन वास्तव में निजी गुण नहीं है।

20

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


15

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

class Model(object):

  def get_a(self):
    if not hasattr(self, "_a"):
      self._a = self.db.lookup("a")
    return self._a

  a = property(get_a)

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


1
क्या आप इसके लिए उपयोग नहीं कर सकते @cached_property?
आदर्श

@ आदर्श - दिलचस्प लगता है। वह कहा है?
detly

मैं इसका उपयोग कर रहा हूं, लेकिन मैं भूल गया कि यह बिल्ट इन नहीं था, लेकिन आप इसे इसके साथ उपयोग कर सकते हैं, pypi.python.org/pypi/cached-property/0.1.5
adarsh

2
दिलचस्प। मुझे लगता है कि इस उत्तर के बाद इसे पहली बार प्रकाशित किया गया था, लेकिन इसे पढ़ने वाले किसी व्यक्ति को शायद इसके बजाय इसका उपयोग करना चाहिए।
21

10

जवाब और टिप्पणियों के माध्यम से पढ़ना, मुख्य विषय लगता है कि उत्तर एक सरल, अभी तक उपयोगी उदाहरण याद आ रहे हैं। मैंने यहां एक बहुत ही सरल को शामिल किया है जो @propertyसज्जाकार के सरल उपयोग को प्रदर्शित करता है । यह एक वर्ग है कि एक उपयोगकर्ता निर्दिष्ट करें और विभिन्न इकाइयों, यानी की एक किस्म का उपयोग कर दूरी माप प्राप्त करने के लिए अनुमति देता है है in_feetया in_metres

class Distance(object):
    def __init__(self):
        # This private attribute will store the distance in metres
        # All units provided using setters will be converted before
        # being stored
        self._distance = 0.0

    @property
    def in_metres(self):
        return self._distance

    @in_metres.setter
    def in_metres(self, val):
        try:
            self._distance = float(val)
        except:
            raise ValueError("The input you have provided is not recognised "
                             "as a valid number")

    @property
    def in_feet(self):
        return self._distance * 3.2808399

    @in_feet.setter
    def in_feet(self, val):
        try:
            self._distance = float(val) / 3.2808399
        except:
            raise ValueError("The input you have provided is not recognised "
                             "as a valid number")

    @property
    def in_parsecs(self):
        return self._distance * 3.24078e-17

    @in_parsecs.setter
    def in_parsecs(self, val):
        try:
            self._distance = float(val) / 3.24078e-17
        except:
            raise ValueError("The input you have provided is not recognised "
                             "as a valid number")

उपयोग:

>>> distance = Distance()
>>> distance.in_metres = 1000.0
>>> distance.in_metres
1000.0
>>> distance.in_feet
3280.8399
>>> distance.in_parsecs
3.24078e-14

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

7

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

@property
def x(self):
    """I'm the 'x' property."""
    if self._x is None:
        self._x = Foo()

    return self._x

6

हां, पोस्ट किए गए मूल उदाहरण के लिए, संपत्ति ठीक उसी तरह काम करेगी जैसे कि केवल एक उदाहरण चर 'x' है।

यह अजगर के गुणों के बारे में सबसे अच्छी बात है। बाहर से, वे उदाहरण चर की तरह काम करते हैं! जो आपको कक्षा के बाहर से उदाहरण चर का उपयोग करने की अनुमति देता है।

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

कई अन्य भाषाएं और प्रोग्रामिंग पाठ्यक्रम निर्देश देंगे कि एक प्रोग्रामर को कभी भी उदाहरण चर का पर्दाफाश नहीं करना चाहिए, और इसके बजाय किसी भी मूल्य के लिए 'गेटर्स' और 'सेटलर्स' का उपयोग करना चाहिए, यहां तक ​​कि प्रश्न में उद्धृत सरल मामला भी।

कई भाषाओं (जैसे जावा) के उपयोग के साथ कक्षा के बाहर कोड

object.get_i()
    #and
object.set_i(value)

#in place of (with python)
object.i
    #and 
object.i = value

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

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


6

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

उदाहरण के लिए यदि आपने Personएक सेटर setage(newage), और एक गेट्टर के साथ कक्षा लिखी है getage(), तो उस उम्र को बढ़ाने के लिए जिसे आपको लिखना होगा:

bob = Person('Robert', 25)
bob.setage(bob.getage() + 1)

लेकिन अगर आपने ageएक संपत्ति बनाई है तो आप बहुत क्लीनर लिख सकते हैं:

bob.age += 1

5

आपके प्रश्न का संक्षिप्त उत्तर, यह है कि आपके उदाहरण में, कोई लाभ नहीं है। आपको संभवतः उस फॉर्म का उपयोग करना चाहिए जिसमें गुण शामिल नहीं हैं।

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


4

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

class reader(property):
    def __init__(self, varname):
        _reader = lambda obj: getattr(obj, varname)
        super(reader, self).__init__(_reader)

class accessor(property):
    def __init__(self, varname, set_validation=None):
        _reader = lambda obj: getattr(obj, varname)
        def _writer(obj, value):
            if set_validation is not None:
               if set_validation(value):
                  setattr(obj, varname, value)
        super(accessor, self).__init__(_reader, _writer)

#example
class MyClass(object):
   def __init__(self):
     self._attr = None

   attr = reader('_attr')

यह मुझे पंसद है। क्या मैं इसे सही तरीके से पढ़ रहा हूं कि केवल पढ़ने वाला ही पढ़ता है जबकि एलेक्टर बिना विलोपन क्षमता के पढ़ा / लिखा जाता है? यद्यपि आप डेटा सत्यापन कैसे जोड़ेंगे? मैं पायथन के लिए बिल्कुल नया हूं, लेकिन मैं सोच रहा हूं कि शायद attr = reader('_attr')लाइन में कॉलबैक जोड़ने का कोई तरीका है या किसी तरह की प्रीचेकिंग attr = if self.__isValid(value): reader('_attr')। सुझाव?
गाबे स्प्रेडलिन

क्षमा करें बस एहसास हुआ कि मैं केवल पढ़ने के लिए डेटा सत्यापन के बारे में पूछ रहा था चर। लेकिन स्पष्ट रूप से यह केवल एक्सेसर वर्ग के सेटर भाग पर लागू होगा। इसलिए इसमें बदलाव attr = reader('_attr')करें attr = accessor('_attr')। धन्यवाद
Gabe Spradlin

आप सही कह रहे हैं कि यदि आप सत्यापन चाहते थे तो आप वैधता को अमान्य करने के लिए एक समारोह जोड़ेंगे और यदि अपवाद (या जो भी व्यवहार आपको पसंद है, जिसमें कुछ भी शामिल नहीं है) को अमान्य माना जाएगा । मैंने उपरोक्त को एक संभव पैटर्न के साथ संशोधित किया है। सत्यापनकर्ता को सही लौटना चाहिए। यह निर्धारित करने के लिए कि सेट होता है या नहीं।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.