@Property डेकोरेटर कैसे काम करता है?


979

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

यह उदाहरण प्रलेखन से है :

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

    def getx(self):
        return self._x
    def setx(self, value):
        self._x = value
    def delx(self):
        del self._x
    x = property(getx, setx, delx, "I'm the 'x' property.")

propertyके तर्क हैं getx, setx, delxऔर कोई दस्तावेज़ स्ट्रिंग।

नीचे दिए गए कोड propertyमें डेकोरेटर के रूप में उपयोग किया जाता है। इसका उद्देश्य xफ़ंक्शन है, लेकिन ऊपर दिए गए कोड में तर्कों में ऑब्जेक्ट फ़ंक्शन के लिए कोई स्थान नहीं है।

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.setterऔर x.deleterसज्जाकार कैसे बनाए जाते हैं? मैं उलझन में हूं।



3
propertyवास्तव में एक वर्ग है (एक फ़ंक्शन नहीं), हालांकि यह संभवत: __init__()जब आप एक वस्तु बनाते हैं, तो विधि को कॉल करते हैं । help(property)टर्मिनल से उपयोग करना व्यावहारिक है। helpकिसी कारण से एक वर्ग भी है।
Br --tsyorfuzthrāx

मुझे लगता है कि यह लिंक एक अच्छा उदाहरण प्रदान करता है: [संपत्ति] ( journaldev.com/14893/python-property-decorator )
शेंग द्वि

4
@ शूल 2-वर्षीय धागा, लेकिन फिर भी: सब कुछ एक वर्ग है। यहां तक ​​कि कक्षाएं भी।
आर्टेमिस अभी भी

2
यह मुझे भी भ्रमित कर रहा था। मुझे आखिरकार एक लेख मिला जो मेरे लिए इसे तोड़ने में सक्षम था। मैं उम्मीद करता हूं कि इससे किसी की मदद होगी। programiz.com/python-programming/property मैं साइट के साथ किसी भी तरह से संबद्ध नहीं हूं।
१०:५५ पर jwwdesign

जवाबों:


1008

property()फ़ंक्शन एक विशेष वर्णनकर्ता वस्तु :

>>> property()
<property object at 0x10ff07940>

यह वह वस्तु है जिसमें अतिरिक्त विधियाँ हैं:

>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>

ये सज्जाकार के रूप में भी काम करते हैं । वे एक नई संपत्ति वस्तु लौटाते हैं:

>>> property().getter(None)
<property object at 0x10ff079f0>

यह पुरानी वस्तु की एक प्रति है, लेकिन प्रतिस्थापित कार्यों में से एक के साथ।

याद रखें, कि @decoratorवाक्यविन्यास सिर्फ वाक्य रचना चीनी है; वाक्य रचना:

@property
def foo(self): return self._foo

वास्तव में के रूप में एक ही बात का मतलब है

def foo(self): return self._foo
foo = property(foo)

इसलिए fooफ़ंक्शन द्वारा प्रतिस्थापित किया जाता हैproperty(foo) , जिसे हमने ऊपर देखा था एक विशेष वस्तु है। फिर जब आप उपयोग करते हैं @foo.setter(), तो आप जो कर रहे हैं वह कॉल हैproperty().setter पद्धति मैंने आपको ऊपर दिखाया था, जो संपत्ति की एक नई प्रति लौटाता है, लेकिन इस बार सेटर फ़ंक्शन के साथ सजाए गए विधि के साथ बदल दिया जाता है।

निम्नलिखित अनुक्रम भी उन डेकोरेटर विधियों का उपयोग करके एक पूर्ण-संपत्ति बनाता है।

पहले हम कुछ काम करते हैं और एक propertyऑब्जेक्ट सिर्फ एक गटर से बनाते हैं :

>>> def getter(self): print('Get!')
... 
>>> def setter(self, value): print('Set to {!r}!'.format(value))
... 
>>> def deleter(self): print('Delete!')
... 
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True

आगे हम .setter()एक सेटर जोड़ने की विधि का उपयोग करते हैं :

>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True

अंतिम हम .deleter()विधि के साथ एक डिलेटर जोड़ते हैं :

>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True

इतना ही नहीं बल्कि, propertyवस्तु एक के रूप में कार्य वर्णनकर्ता वस्तु , तो यह है .__get__(), .__set__()और .__delete__()तरीकों रही, स्थापित करने और हटाने उदाहरण विशेषता में हुक करने:

>>> class Foo: pass
... 
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!

डिस्क्रिप्टर हॉव्टो में शुद्ध पायथन नमूनाproperty() प्रकार का कार्यान्वयन शामिल है :

class Property:
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

10
बहुत अच्छा। आप इस तथ्य को जोड़ सकते हैं कि Foo.prop = propआप Foo().prop = 5; pront Foo().prop; del Foo().propवांछित परिणाम के साथ क्या कर सकते हैं ।
glglgl

12
विधि ऑब्जेक्ट्स मक्खी पर बनाए जाते हैं और यदि उपलब्ध हो तो उसी मेमोरी लोकेशन का पुन: उपयोग कर सकते हैं।
मार्टिज़न पीटरर्स

1
@MarkusMeskanen: मैं इसके बजाय डंडर type()विशेषताओं तक पहुँचने के लिए उपयोग करता हूं और विधियों का उपयोग मानक कार्यों और ऑपरेटरों द्वारा विस्तार बिंदुओं के रूप में किया जाता है।
मार्टिन पीटर्स

2
@MarkusMeskanen: क्योंकि वस्तु अपरिवर्तनीय है, और यदि आपने इसे जगह में उत्परिवर्तित किया है तो आप इसे उपवर्ग में विशेषज्ञ नहीं बना सकते।
मार्टिन पीटर्स

5
@MarkusMeskanen: सेटर के बिना पाइथन ओवरराइडिंग गटर देखें ; अगर @human.name.getterबदल propertyयथा-स्थान वस्तु के बजाय एक नई लौटने के लिए, human.nameविशेषता बदल जाएगा, कि सुपर क्लास के व्यवहार को बदलने।
Martijn Pieters

200

डॉक्यूमेंटेशन कहता है कि यह आसानी से आसानी से प्रॉपर्टी बनाने का शॉर्टकट है। इसलिए

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

के बराबर है

def getx(self):
    return self._x
x = property(getx)

19
पूर्ण संदर्भ (सबसे उत्कीर्ण उत्तर) अच्छा है, लेकिन यह उत्तर व्यावहारिक रूप से यह पता लगाने के लिए उपयोगी है कि किसी और ने @propertyअपनी कक्षा में एक सज्जाकार के रूप में क्यों इस्तेमाल किया था ।
जोजफ

1
@property का उपयोग तब भी किया जा सकता है जब आप किसी वर्ग में एक विशेषता जोड़ना चाहते हैं और उस वर्ग की पहले से बनाई गई वस्तुओं के साथ संगतता बनाए रखने की आवश्यकता होती है (जैसे कि अचार फ़ाइल में सहेजा जा सकता है)।
एंडीपी

111

यहां एक न्यूनतम उदाहरण दिया गया है कि @propertyइसे कैसे लागू किया जा सकता है:

class Thing:
    def __init__(self, my_word):
        self._word = my_word 
    @property
    def word(self):
        return self._word

>>> print( Thing('ok').word )
'ok'

अन्यथा wordएक संपत्ति के बजाय एक विधि बनी हुई है।

class Thing:
    def __init__(self, my_word):
        self._word = my_word
    def word(self):
        return self._word

>>> print( Thing('ok').word() )
'ok'

1
यह उदाहरण कैसा लगेगा यदि शब्द () फ़ंक्शन / संपत्ति को init में परिभाषित करने की आवश्यकता है ?
JJ

5
क्या कोई यह समझा सकता है कि मैं सिर्फ संपत्ति रखने के लिए एक संपत्ति सज्जाकार क्यों बनाऊंगा, self.word = my_wordजो सिर्फ होने के बजाय - जो फिर उसी तरह से काम करेगाprint( Thing('ok').word ) = 'ok'
सिल्वरलैश

1
@SilverSlash यह केवल एक सरल उदाहरण है, एक वास्तविक उपयोग-मामले में अधिक जटिल विधि शामिल होगी
एलेक्सजेन

क्या आप कृपया मुझे समझा सकते हैं, कैसे मुद्रण Thing('ok').wordसमारोह को आंतरिक रूप से रनटाइम पर कॉल करता है?
विक्रोबोट

83

पहला भाग सरल है:

@property
def x(self): ...

के समान है

def x(self): ...
x = property(x)
  • जो, बदले में, propertyबस एक गेट्टर के साथ बनाने के लिए सरलीकृत सिंटैक्स है ।

अगला कदम सेटर और डेलेटर के साथ इस संपत्ति का विस्तार करना होगा। और यह उपयुक्त विधियों के साथ होता है:

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

एक नई संपत्ति लौटाता है जो पुराने xप्लस और दिए गए सेटर से सब कुछ प्राप्त करता है ।

x.deleter उसी तरह काम करता है।


49

यह निम्नलिखित है:

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

के समान है:

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

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, _x_set, _x_del, 
                    "I'm the 'x' property.")

के समान है:

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

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, doc="I'm the 'x' property.")
    x = x.setter(_x_set)
    x = x.deleter(_x_del)

के समान है:

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

    def _x_get(self):
        return self._x
    x = property(_x_get, doc="I'm the 'x' property.")

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

    def _x_del(self):
        del self._x
    x = x.deleter(_x_del)

जो निम्नानुसार है:

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

4
पहला और अंतिम कोड उदाहरण समान हैं (क्रिया)।
एडोमास बलूका

47

नीचे एक और उदाहरण है कि कैसे @propertyमदद कर सकता है जब किसी को कोड को रिफलेक्टर करना होता है जो यहां से लिया गया है (मैं केवल इसे नीचे संक्षेप में बताता हूं):

आप Moneyइस तरह एक वर्ग बनाया कल्पना कीजिए :

class Money:
    def __init__(self, dollars, cents):
        self.dollars = dollars
        self.cents = cents

और एक उपयोगकर्ता इस वर्ग के आधार पर एक पुस्तकालय बनाता है जहां वह / वह उदाहरण के लिए उपयोग करता है

money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.

अब मान लेते हैं कि आप अपनी Moneyकक्षा को बदलने dollarsऔर centsविशेषताओं से छुटकारा पाने का निर्णय लेते हैं, लेकिन इसके बजाय केवल कुल राशि को ट्रैक करने का निर्णय लेते हैं:

class Money:
    def __init__(self, dollars, cents):
        self.total_cents = dollars * 100 + cents

यदि उपर्युक्त उपयोगकर्ता अब पहले की तरह अपनी लाइब्रेरी चलाने की कोशिश करता है

money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))

यह एक त्रुटि के परिणामस्वरूप होगा

गुण: 'धन' वस्तु का कोई गुण 'डॉलर' नहीं है

इसका मतलब है कि अब हर कोई जो आपके मूल Moneyवर्ग पर निर्भर है, को कोड की सभी लाइनों को बदलना होगा, जहां dollarsऔर centsइसका उपयोग किया जाता है जो बहुत दर्दनाक हो सकता है ... तो, यह कैसे बचा जा सकता है? का उपयोग करके@property !

इस तरह से:

class Money:
    def __init__(self, dollars, cents):
        self.total_cents = dollars * 100 + cents

    # Getter and setter for dollars...
    @property
    def dollars(self):
        return self.total_cents // 100

    @dollars.setter
    def dollars(self, new_dollars):
        self.total_cents = 100 * new_dollars + self.cents

    # And the getter and setter for cents.
    @property
    def cents(self):
        return self.total_cents % 100

    @cents.setter
    def cents(self, new_cents):
        self.total_cents = 100 * self.dollars + new_cents

जब हम अब अपने पुस्तकालय से बुलाते हैं

money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.

यह उम्मीद के मुताबिक काम करेगा और हमें अपनी लाइब्रेरी में कोड की एक भी लाइन नहीं बदलनी होगी! वास्तव में, हमें यह भी पता नहीं होगा कि हम जिस लाइब्रेरी पर निर्भर हैं, वह बदल गई है।

इसके अलावा setterठीक काम करता है:

money.dollars += 2
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 12 cents.

money.cents += 10
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 22 cents.

आप @propertyअमूर्त कक्षाओं में भी उपयोग कर सकते हैं ; मैं यहां एक न्यूनतम उदाहरण देता हूं ।


आपका सारांश बहुत अच्छा है, वेबसाइट जो उदाहरण लेता है वह थोड़ा अजीब है .. एक शुरुआत पूछेगा .. हम सिर्फ क्यों नहीं चिपक सकते self.dollar = dollars? हमने @property के साथ बहुत कुछ किया है, लेकिन ऐसा लगता है कि कोई एक्स्ट्रेक्ट कार्यक्षमता नहीं जोड़ी गई है।
शेंग द्वि

1
@ShengBi: वास्तविक उदाहरण पर अधिक ध्यान न दें, लेकिन अंतर्निहित सिद्धांत पर अधिक: यदि - कभी भी किस कारण से - आपको कोड को रिफलेक्टर करना है, तो आप किसी अन्य के कोड को प्रभावित किए बिना ऐसा कर सकते हैं।
क्लेब

21

मैंने यहां सभी पोस्ट पढ़ीं और महसूस किया कि हमें एक वास्तविक जीवन उदाहरण की आवश्यकता हो सकती है। क्यों, वास्तव में, हमारे पास @property है? इसलिए, एक फ्लास्क ऐप पर विचार करें जहां आप प्रमाणीकरण प्रणाली का उपयोग करते हैं। आप एक मॉडल की घोषणा करते हैं models.py:

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))

    ...

    @property
    def password(self):
        raise AttributeError('password is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

इस कोड में हमने "छिपी" विशेषता passwordका उपयोग करते हुए @property, AttributeErrorजब आप इसे सीधे एक्सेस करने का प्रयास करते हैं, तो इसका उपयोग करते हैं, जबकि हमने वास्तविक उदाहरण चर सेट करने के लिए @ property.setter का उपयोग किया था password_hash

अब auth/views.pyहम इसमें किसी उपयोगकर्ता को तत्काल भेज सकते हैं:

...
@auth.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        user = User(email=form.email.data,
                    username=form.username.data,
                    password=form.password.data)
        db.session.add(user)
        db.session.commit()
...

नोटिस विशेषता passwordजो किसी उपयोगकर्ता द्वारा फॉर्म भरने पर पंजीकरण फॉर्म से आती है। पासवर्ड की पुष्टि सामने के छोर पर होती है EqualTo('password', message='Passwords must match')(यदि आप सोच रहे हैं, लेकिन यह एक अलग विषय से संबंधित फ्लास्क फॉर्म है)।

मुझे उम्मीद है कि यह उदाहरण उपयोगी होगा


18

इस बिंदु को बहुत से लोगों ने साफ़ किया है लेकिन यहाँ एक सीधा बिंदु है जिसे मैं खोज रहा था। यह वही है जो मुझे लगता है कि @property डेकोरेटर के साथ शुरू करना महत्वपूर्ण है। जैसे: -

class UtilityMixin():
    @property
    def get_config(self):
        return "This is property"

फ़ंक्शन "get_config ()" की कॉलिंग इस तरह काम करेगी।

util = UtilityMixin()
print(util.get_config)

यदि आप ध्यान दें कि मैंने फ़ंक्शन को कॉल करने के लिए "()" कोष्ठक का उपयोग नहीं किया है। यह मूल चीज है जिसे मैं @property डेकोरेटर के लिए खोज रहा था। ताकि आप अपने फंक्शन को एक वेरिएबल की तरह ही इस्तेमाल कर सकें।


1
बहुत उपयोगी बिंदु जो इस अमूर्त अवधारणा को घनीभूत करने में मदद करता है।
Info5ek

18

शुरुआत करते हैं पायथन डेकोरेटर्स से।

पायथन डेकोरेटर एक फ़ंक्शन है जो पहले से परिभाषित फ़ंक्शन में कुछ अतिरिक्त फ़ंक्शंस जोड़ने में मदद करता है।

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

निम्नलिखित कोड स्निपेट पर विचार करें।

def decorator_func(fun):
    def wrapper_func():
        print("Wrapper function started")
        fun()
        print("Given function decorated")
        # Wrapper function add something to the passed function and decorator 
        # returns the wrapper function
    return wrapper_func

def say_bye():
    print("bye!!")

say_bye = decorator_func(say_bye)
say_bye()

# Output:
#  Wrapper function started
#  bye
#  Given function decorated

यहाँ, हम कह सकते हैं कि डेकोरेटर फ़ंक्शन ने हमारे say_hello फ़ंक्शन को संशोधित किया और इसमें कोड की कुछ अतिरिक्त लाइनें जोड़ीं।

डेकोरेटर के लिए पायथन सिंटैक्स

def decorator_func(fun):
    def wrapper_func():
        print("Wrapper function started")
        fun()
        print("Given function decorated")
        # Wrapper function add something to the passed function and decorator 
        # returns the wrapper function
    return wrapper_func

@decorator_func
def say_bye():
    print("bye!!")

say_bye()

चलो एक मामले के परिदृश्य की तुलना में सब कुछ समाप्‍त कर देते हैं, लेकिन इससे पहले आइए कुछ ऊप्स प्रिंसीपल के बारे में बात करते हैं।

डेटा इनकैप्सुलेशन के सिद्धांत को सुनिश्चित करने के लिए कई ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग लैंग्वेज में गेटर्स और सेटर का उपयोग किया जाता है (इसे इन डेटा पर काम करने वाले तरीकों के साथ डेटा के बंडल के रूप में देखा जाता है।)

ये तरीके निश्चित रूप से डेटा को पुनः प्राप्त करने के लिए और डेटा को बदलने के लिए सेटर हैं।

इस सिद्धांत के अनुसार, एक वर्ग की विशेषताओं को अन्य कोड से छिपाने और उनकी रक्षा करने के लिए निजी बनाया जाता है।

हाँ, @property मूल रूप से एक है से गेटर्स और सेटर का उपयोग करने के लिए पायथोनिक तरीका है।

पायथन में एक महान अवधारणा है जिसे संपत्ति कहा जाता है जो ऑब्जेक्ट-ओरिएंटेड प्रोग्रामर के जीवन को बहुत सरल बनाता है।

चलिए हम मान लेते हैं कि आप एक ऐसा वर्ग बनाने का निर्णय लेते हैं जो तापमान को डिग्री सेल्सियस में संग्रहित कर सके।

class Celsius:
def __init__(self, temperature = 0):
    self.set_temperature(temperature)

def to_fahrenheit(self):
    return (self.get_temperature() * 1.8) + 32

def get_temperature(self):
    return self._temperature

def set_temperature(self, value):
    if value < -273:
        raise ValueError("Temperature below -273 is not possible")
    self._temperature = value

Refactored Code, Here यह है कि हम इसे संपत्ति के साथ कैसे प्राप्त कर सकते हैं।

पायथन में, संपत्ति () एक अंतर्निहित फ़ंक्शन है जो एक संपत्ति ऑब्जेक्ट बनाता है और वापस करता है।

एक प्रॉपर्टी ऑब्जेक्ट में तीन तरीके होते हैं, गेट्टर (), सेटर (), और डिलीट ()।

class Celsius:
def __init__(self, temperature = 0):
    self.temperature = temperature

def to_fahrenheit(self):
    return (self.temperature * 1.8) + 32

def get_temperature(self):
    print("Getting value")
    return self.temperature

def set_temperature(self, value):
    if value < -273:
        raise ValueError("Temperature below -273 is not possible")
    print("Setting value")
    self.temperature = value

temperature = property(get_temperature,set_temperature)

यहाँ,

temperature = property(get_temperature,set_temperature)

के रूप में तोड़ा जा सकता था,

# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)

नोट करने के लिए बिंदु:

  • get_taper एक विधि के बजाय एक संपत्ति बना हुआ है।

अब आप लिखकर तापमान के मान को प्राप्त कर सकते हैं।

C = Celsius()
C.temperature
# instead of writing C.get_temperature()

हम आगे पर जा सकते हैं और नाम नहीं परिभाषित get_temperature और set_temperature के रूप में वे अनावश्यक हैं और वर्ग नामस्थान को दूषित।

Pythonic तरीका ऊपर समस्या से निपटने के उपयोग करने के लिए है @property

class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    @property
    def temperature(self):
        print("Getting value")
        return self.temperature

    @temperature.setter
    def temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self.temperature = value

नोट करने के लिए अंक -

  1. एक विधि जिसका उपयोग मूल्य प्राप्त करने के लिए किया जाता है उसे "@property" से सजाया जाता है।
  2. जिस विधि को सेटर के रूप में कार्य करना होता है उसे "@ temperature.setter" से सजाया जाता है, यदि फ़ंक्शन को "x" कहा जाता था, तो हमें इसे "@ x.setter" से सजाना होगा।
  3. हमने एक ही नाम के साथ "दो" विधियां लिखीं और "डिफ तापमान (स्व)" और "डिफ टेम्परेचर (सेल्फ, एक्स)" के मापदंडों की एक अलग संख्या।

जैसा कि आप देख सकते हैं, कोड निश्चित रूप से कम सुरुचिपूर्ण है।

अब, एक वास्तविक जीवन के व्यावहारिक वैज्ञानिक के बारे में बात करते हैं।

मान लीजिए कि आपने निम्नानुसार एक वर्ग तैयार किया है:

class OurClass:

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


y = OurClass(10)
print(y.x)

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

और एक भाग्यशाली दिन, एक विश्वसनीय ग्राहक हमारे पास आया और सुझाव दिया कि "x" को 0 और 1000 के बीच का मान होना चाहिए, यह वास्तव में एक भयानक परिदृश्य है!

गुणों के कारण यह आसान है: हम "x" का एक संपत्ति संस्करण बनाते हैं।

class OurClass:

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

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

    @x.setter
    def x(self, x):
        if x < 0:
            self.__x = 0
        elif x > 1000:
            self.__x = 1000
        else:
            self.__x = x

यह बहुत अच्छा है, यह नहीं है: आप सबसे सरल कार्यान्वयन कल्पना के साथ शुरू कर सकते हैं, और आप इंटरफ़ेस बदलने के लिए बिना बाद में एक संपत्ति संस्करण में स्थानांतरित करने के लिए स्वतंत्र हैं! तो गुण सिर्फ गेटर्स और सेटर के लिए एक प्रतिस्थापन नहीं हैं!

आप इस कार्यान्वयन को यहां देख सकते हैं


2
सेटिंग करते समय (जो तात्कालिकता का मतलब है) आपका सेल्सियस वर्ग असीम रूप से पुनरावृत्ति करने वाला है।
टेड पेट्रो

1
@ पेटू मैं तुम्हें नहीं मिला? सेटिंग करते समय यह असीम रूप से कैसे पुनरावृत्ति करेगा?
दिव्यांशु रावत

यह वास्तव में स्पष्ट नहीं है ... लोग पूछ रहे हैं क्यों, लेकिन उदाहरण आश्वस्त नहीं कर रहा है ...
शेंग द्वि

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

1
शीर्ष मतदान उत्तरों की तुलना में, यह मनुष्यों के लिए बनाया गया है; धन्यवाद।
Info5ek

6

property पीछे एक वर्ग है @propertyडेकोरेटर के ।

आप इसे हमेशा देख सकते हैं:

print(property) #<class 'property'>

मैंने सिंटैक्स help(property)को दिखाने के लिए उदाहरण को फिर से लिखा है@property

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

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

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

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

c = C()
c.x="a"
print(c.x)

property()वाक्यविन्यास के लिए कार्यात्मक रूप से समान है :

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

    def g(self):
        return self._x

    def s(self, v):
        self._x = v

    def d(self):
        del self._x

    prop = property(g,s,d)

c = C()
c.x="a"
print(c.x)

कोई फर्क नहीं पड़ता कि हम संपत्ति का उपयोग कैसे करते हैं जैसा कि आप देख सकते हैं।

प्रश्न का उत्तर देने के लिए @propertyडेकोरेटर को propertyकक्षा के माध्यम से लागू किया जाता है ।


तो, सवाल propertyकक्षा को थोड़ा समझाने का है । यह रेखा:

prop = property(g,s,d)

इनिशियलाइज़ेशन था। हम इसे इस तरह से फिर से लिख सकते हैं:

prop = property(fget=g,fset=s,fdel=d)

का अर्थ fget, fsetऔर fdel:

 |    fget
 |      function to be used for getting an attribute value
 |    fset
 |      function to be used for setting an attribute value
 |    fdel
 |      function to be used for del'ing an attribute
 |    doc
 |      docstring

अगली छवि में वर्ग से हमारे पास मौजूद ट्रिपल दिखाए गए हैं property:

यहां छवि विवरण दर्ज करें

__get__, __set__और __delete__वहाँ ओवरराइड हो रहे हैं । यह पायथन में डिस्क्रिप्टर पैटर्न का कार्यान्वयन है।

सामान्य तौर पर, एक विवरणक "बाध्यकारी व्यवहार" के साथ एक वस्तु विशेषता है, जिसका एक विशेषता अभिगम विवरणक प्रोटोकॉल में विधियों द्वारा ओवरराइड किया गया है।

हम यह भी संपत्ति का उपयोग कर सकते setter, getterऔर deleterतरीकों संपत्ति के लिए बाध्य करने के लिए समारोह। अगला उदाहरण देखें। s2वर्ग की विधि Cसंपत्ति को दोगुना कर देगी ।

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

    def g(self):
        return self._x

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

    def d(self):
        del self._x

    def s2(self,x):
        self._x=x+x


    x=property(g)
    x=x.setter(s)
    x=x.deleter(d)      


c = C()
c.x="a"
print(c.x) # outputs "a"

C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x) # outputs "aa"

1

एक संपत्ति को दो तरीकों से घोषित किया जा सकता है।

  • एक विशेषता के लिए गेट्टर, सेटर विधियां बनाना और फिर उन्हें प्रॉपर्टी फ़ंक्शन के तर्क के रूप में पारित करना
  • @Property डेकोरेटर का उपयोग करना ।

आप कुछ उदाहरणों पर एक नज़र डाल सकते हैं जो मैंने अजगर में गुणों के बारे में लिखा है ।


क्या आप अपने उत्तर को यह कहते हुए अद्यतन कर सकते हैं कि संपत्ति एक वर्ग है इसलिए मैं उत्थान कर सकता हूं।
प्रोस्टि

1

सबसे अच्छा स्पष्टीकरण यहाँ पाया जा सकता है: पायथन @Property समझाया - कैसे और कब उपयोग करें? (पूर्ण उदाहरण) सेल्वा प्रभाकरन द्वारा | 5 नवंबर 2018 को पोस्ट किया गया

इसने मुझे यह समझने में मदद की कि न केवल कैसे।

https://www.machinelearningplus.com/python/python-property/


0

यहाँ एक और उदाहरण है:

##
## Python Properties Example
##
class GetterSetterExample( object ):
    ## Set the default value for x ( we reference it using self.x, set a value using self.x = value )
    __x = None


##
## On Class Initialization - do something... if we want..
##
def __init__( self ):
    ## Set a value to __x through the getter / setter... Since __x is defined above, this doesn't need to be set...
    self.x = 1234

    return None


##
## Define x as a property, ie a getter - All getters should have a default value arg, so I added it - it will not be passed in when setting a value, so you need to set the default here so it will be used..
##
@property
def x( self, _default = None ):
    ## I added an optional default value argument as all getters should have this - set it to the default value you want to return...
    _value = ( self.__x, _default )[ self.__x == None ]

    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Get x = ' + str( _value ) )

    ## Return the value - we are a getter afterall...
    return _value


##
## Define the setter function for x...
##
@x.setter
def x( self, _value = None ):
    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Set x = ' + str( _value ) )

    ## This is to show the setter function works.... If the value is above 0, set it to a negative value... otherwise keep it as is ( 0 is the only non-negative number, it can't be negative or positive anyway )
    if ( _value > 0 ):
        self.__x = -_value
    else:
        self.__x = _value


##
## Define the deleter function for x...
##
@x.deleter
def x( self ):
    ## Unload the assignment / data for x
    if ( self.__x != None ):
        del self.__x


##
## To String / Output Function for the class - this will show the property value for each property we add...
##
def __str__( self ):
    ## Output the x property data...
    print( '[ x ] ' + str( self.x ) )


    ## Return a new line - technically we should return a string so it can be printed where we want it, instead of printed early if _data = str( C( ) ) is used....
    return '\n'

##
##
##
_test = GetterSetterExample( )
print( _test )

## For some reason the deleter isn't being called...
del _test.x

मूल रूप से, सी (ऑब्जेक्ट) उदाहरण के समान है, सिवाय इसके कि मैं एक्स का उपयोग कर रहा हूं ... मैं भी __in में आरंभ नहीं करता हूं - ... अच्छा .. मैं करता हूं, लेकिन इसे हटाया जा सकता है क्योंकि __x को भाग के रूप में परिभाषित किया गया है कक्षा के ...।

आउटपुट है:

[ Test Class ] Set x = 1234
[ Test Class ] Get x = -1234
[ x ] -1234

और अगर मैं में self.x = 1234 बाहर टिप्पणी init तो उत्पादन होता है:

[ Test Class ] Get x = None
[ x ] None

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

[ Test Class ] Get x = 0
[ x ] 0

ध्यान दें: गेटर लॉजिक वहाँ है कि मूल्य को इसके द्वारा हेरफेर किया जाए ताकि यह सुनिश्चित हो सके कि यह हेरफेर किया गया है - प्रिंट स्टेटमेंट के लिए भी ...

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

नोट: इस फ़ोरम में कोड आउटपुट टूट गया है - मुझे काम करने के लिए कोड के पहले भाग में स्पेस जोड़ना था - जब कॉपी / पेस्ट करना सुनिश्चित करें कि आप सभी स्पेस को टैब्स में कनवर्ट करते हैं .... मैं पायथन के लिए टैब का उपयोग करता हूं क्योंकि एक फाइल जो 10,000 लाइन्स की है, फाइल्स को 512KB से 1MB तक स्पेस के साथ और 100 से 200KB तक टैब के साथ किया जा सकता है, जो फाइल साइज के बड़े पैमाने पर अंतर और प्रोसेसिंग टाइम में कमी के बराबर है ...

टैब प्रति उपयोगकर्ता भी समायोजित किया जा सकता है - इसलिए यदि आप 2 रिक्त स्थान की चौड़ाई, 4, 8 या जो कुछ भी आप इसे पसंद कर सकते हैं उसका अर्थ यह है कि यह डेवलपर्स के लिए आंख-दृष्टि की कमी के लिए विचारशील है।

नोट: फ़ोरम सॉफ़्टवेयर में बग के कारण वर्ग में परिभाषित सभी फ़ंक्शन ठीक से इंडेंट नहीं किए गए हैं - यदि आप कॉपी या पेस्ट करते हैं तो आप इसे इंडेंट कर सकते हैं


-3

एक टिप्पणी: मेरे लिए, पायथन 2.x के लिए, @propertyजब मुझे विरासत में नहीं मिला था, तो विज्ञापन के रूप में काम नहीं किया था object:

class A():
    pass

लेकिन काम किया जब:

class A(object):
    pass

पायथन 3 के लिए, हमेशा काम किया।


5
ऐसा इसलिए है क्योंकि पायथन 2 में, एक वर्ग जो विरासत में नहीं आता है objectवह एक पुरानी शैली की श्रेणी है, और पुरानी शैली की कक्षाएं वर्णक प्रोटोकॉल का समर्थन नहीं करती हैं (जो propertyकि जिस तरह से काम करती है वह लागू होती है)। पायथन 3 में, पुरानी शैली की कक्षाएं किसी भी अधिक मौजूद नहीं हैं; सभी वर्ग हैं जिन्हें हमने पायथन 2 में नई शैली की कक्षाएं कहा है
21:39
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.