पायथन केवल पढ़ने के लिए संपत्ति


95

मुझे नहीं पता कि कब विशेषता निजी होनी चाहिए और अगर मुझे संपत्ति का उपयोग करना चाहिए।

मैंने हाल ही में पढ़ा कि बसने वाले और पाने वाले अजगर नहीं हैं और मुझे संपत्ति डेकोरेटर का उपयोग करना चाहिए। यह ठीक है।

लेकिन क्या होगा अगर मेरे पास विशेषता है, जिसे कक्षा के बाहर से सेट नहीं किया जाना चाहिए, लेकिन पढ़ा जा सकता है (केवल पढ़ने के लिए विशेषता)। क्या यह विशेषता निजी होनी चाहिए, और निजी से मेरा मतलब अंडरस्कोर से है, जैसे कि self._x? यदि हाँ, तो बिना गटर का उपयोग किए मैं इसे कैसे पढ़ सकता हूं? केवल विधि जिसे मैं जानता हूं अभी लिखना है

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

इस तरह से मैं विशेषता को पढ़ सकता हूं obj.xलेकिन मैं इसे सेट नहीं कर सकता obj.x = 1इसलिए यह ठीक है।

लेकिन क्या मुझे वास्तव में उस ऑब्जेक्ट को सेट करने की परवाह करनी चाहिए जो सेट नहीं होनी चाहिए? शायद मुझे इसे छोड़ देना चाहिए। लेकिन तब मैं फिर से अंडरस्कोर का उपयोग नहीं कर सकता क्योंकि पढ़ना obj._xउपयोगकर्ता के लिए अजीब है, इसलिए मुझे उपयोग करना चाहिए obj.xऔर फिर से उपयोगकर्ता को पता नहीं है कि उसे यह विशेषता सेट नहीं करनी चाहिए।

आपकी राय और अभ्यास क्या है?


1
एक संपत्ति का विचार यह है कि यह एक विशेषता की तरह व्यवहार करता है लेकिन इसमें अतिरिक्त कोड हो सकता है। यदि आप चाहते हैं कि सभी को एक मूल्य मिल जाए, तो मैं भी परेशान नहीं होगा: बस उपयोग करें self.xऔर भरोसा रखें कि कोई भी नहीं बदलेगा x। यदि यह सुनिश्चित करना कि xबदला नहीं जा सकता है, तो एक संपत्ति का उपयोग करें।
li.davidm

इसके अलावा, _xयह बिल्कुल अजीब नहीं है: सम्मेलन द्वारा , इसका मतलब कुछ "निजी" है।
li.davidm

1
मेरा मतलब था कि _x से पढ़ना विषम है। _X नाम ही नहीं। अगर उपयोगकर्ता _x से सीधे पढ़ रहा है तो वह गैर-जिम्मेदार है।
राफेल żużyński 1

3
जरूरी! आपकी कक्षा को एक नई शैली वाली कक्षा होना चाहिए object, जो वास्तव में आपको सेटिंग बंद करने के लिए विरासत में मिली है obj.x। एक पुरानी शैली के वर्ग पर आप वास्तव में अभी भी सेट कर सकते हैं obj.x, बहुत अप्रत्याशित परिणामों के साथ।
इयान एच

केवल-पढ़ने के लिए कई मान्य कारण हैं। एक तब होता है जब आपके पास एक मूल्य होता है जिसमें दो अन्य (रीड / राइट) मानों का विलय होता है। आप इसे एक विधि में कर सकते हैं, लेकिन आप इसे केवल संपत्ति में भी पढ़ सकते हैं।
दार्शनिक

जवाबों:


68

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


26
ऐसा लगता है कि आपका उत्तर अपने आप में विरोधाभास है। आप कहते हैं कि उपयोगकर्ताओं को ज़िम्मेदार होना चाहिए और चीजों को सही तरीके से उपयोग करना चाहिए, फिर आप कहते हैं कि कभी-कभी यह एक विशेषता के लिए समझ में नहीं आता है और संपत्ति प्राप्त करना एक पूर्वनिर्मित तरीका है। मेरी राय में आप विशेषता निर्धारित या नहीं कर सकते। केवल सवाल यह है कि क्या मुझे इस पोशाक की सुरक्षा करनी चाहिए या इसे छोड़ देना चाहिए। बीच में कोई उत्तर नहीं होना चाहिए।
राफेल żużyński

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

9
लेकिन जिम्मेदार उपयोगकर्ता attr सेट करने की कोशिश नहीं करेगा कि सचमुच सेट नहीं किया जा सकता है। और फिर से ज़िम्मेदार नहीं उपयोगकर्ता यह सुनिश्चित करेगा कि शाब्दिक रूप से सेट किया जा सकता है और अपने सेट के कारण कोड में कहीं और त्रुटि उठाएगा। इसलिए अंत में दोनों अटर को सेट नहीं किया जा सकता है। क्या मुझे दोनों पर संपत्ति का उपयोग करना चाहिए या किसी पर भी इसका उपयोग नहीं करना चाहिए?
राफेल żużyński

8
लेकिन जिम्मेदार उपयोगकर्ता को यह निर्धारित करने का प्रयास नहीं करना चाहिए कि शाब्दिक रूप से सेट नहीं किया जा सकता है। प्रोग्रामिंग में, अगर कुछ सख्ती से गैर-निपटान योग्य मूल्य है, तो जिम्मेदार या समझदार चीज यह सुनिश्चित करना है कि यह नहीं हो सकता है। ये छोटी चीजें सभी विश्वसनीय कार्यक्रमों में योगदान करती हैं।
रोबिन स्मिथ

6
यह एक स्थिति है जो बहुत से लोग और भाषाएं लेते हैं। यदि यह ऐसी स्थिति है जिसे आप गैर-परक्राम्य पाते हैं, तो शायद आपको पायथन का उपयोग नहीं करना चाहिए।
सिलास रे

72

बस मेरे दो सेंट, सिलास रे सही रास्ते पर हैं, हालांकि मुझे ऐसा लगता है कि एक उदाहरण जोड़ना है। ;-)

पायथन एक प्रकार-असुरक्षित भाषा है और इस प्रकार आपको एक उचित (समझदार) व्यक्ति की तरह कोड का उपयोग करने के लिए हमेशा अपने कोड के उपयोगकर्ताओं पर भरोसा करना होगा।

प्रति पीईपी 8 :

केवल गैर-सार्वजनिक तरीकों और उदाहरण चर के लिए एक प्रमुख अंडरस्कोर का उपयोग करें।

क्लास में 'रीड-ओनली' प्रॉपर्टी रखने के लिए @property, आप सजावट का उपयोग कर सकते हैं , आपको objectनई शैली की कक्षाओं का उपयोग करने के लिए ऐसा करने की आवश्यकता होगी ।

उदाहरण:

>>> class A(object):
...     def __init__(self, a):
...         self._a = a
...
...     @property
...     def a(self):
...         return self._a
... 
>>> a = A('test')
>>> a.a
'test'
>>> a.a = 'pleh'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

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

3
लेकिन आपको अभी भी याद रखना चाहिए, कि इस विधि का उपयोग करके उत्परिवर्तित वस्तुओं को वैसे भी बदला जा सकता है। उदाहरण के लिए यदि self.__a = [], आप अभी भी ऐसा कर सकते हैं a.a.append('anything')और यह काम करेगा।
इगोर

3
यह मेरे लिए स्पष्ट नहीं है कि इस उत्तर पर "उचित (समझदार) व्यक्ति" क्या असर डालता है। क्या आप उन चीजों के प्रकार के बारे में अधिक स्पष्ट हो सकते हैं जिन्हें आप एक उचित व्यक्ति समझते हैं और नहीं करेंगे?
winni2k

3
मेरे लिए @property सजावट का उपयोग करने के लिए, आपको ऑब्जेक्ट से इनहेरिट करने की आवश्यकता होगी जब आप ऐसा करते हैं तो इस उत्तर का पूरा बिंदु था। धन्यवाद।
अक्की

2
@ किमी को कभी भी बग को कोड में घुसने की अनुमति नहीं देने का एकमात्र तरीका कोड लिखना कभी नहीं है।
अलेचन

55

यहाँ इस धारणा से बचने का एक तरीका है कि

सभी उपयोगकर्ता वयस्कों की सहमति दे रहे हैं, और इस प्रकार वे स्वयं चीजों को सही ढंग से उपयोग करने के लिए जिम्मेदार हैं।

कृपया नीचे मेरा अपडेट देखें

उपयोग करना @property, बहुत क्रिया है जैसे:

   class AClassWithManyAttributes:
        '''refactored to properties'''
        def __init__(a, b, c, d, e ...)
             self._a = a
             self._b = b
             self._c = c
             self.d = d
             self.e = e

        @property
        def a(self):
            return self._a
        @property
        def b(self):
            return self._b
        @property
        def c(self):
            return self._c
        # you get this ... it's long

का उपयोग करते हुए

कोई अंडरस्कोर नहीं: यह एक सार्वजनिक चर है।
एक अंडरस्कोर: यह एक संरक्षित चर है।
दो अंडरस्कोर: यह एक निजी चर है।

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

तो हम क्या करे? क्या हम पाइथन में केवल गुण पढ़ने पर छोड़ देते हैं?

देखो! read_only_propertiesबचाव के लिए डेकोरेटर!

@read_only_properties('readonly', 'forbidden')
class MyClass(object):
    def __init__(self, a, b, c):
        self.readonly = a
        self.forbidden = b
        self.ok = c

m = MyClass(1, 2, 3)
m.ok = 4
# we can re-assign a value to m.ok
# read only access to m.readonly is OK 
print(m.ok, m.readonly) 
print("This worked...")
# this will explode, and raise AttributeError
m.forbidden = 4

तुम पूछो:

कहां से read_only_propertiesआ रहा है?

खुशी है कि आपने पूछा, यहाँ read_only_properties के लिए स्रोत है :

def read_only_properties(*attrs):

    def class_rebuilder(cls):
        "The class decorator"

        class NewClass(cls):
            "This is the overwritten class"
            def __setattr__(self, name, value):
                if name not in attrs:
                    pass
                elif name not in self.__dict__:
                    pass
                else:
                    raise AttributeError("Can't modify {}".format(name))

                super().__setattr__(name, value)
        return NewClass
    return class_rebuilder

अपडेट करें

मुझे उम्मीद नहीं थी कि इस जवाब पर इतना ध्यान जाएगा। हैरानी की बात है कि यह करता है। इसने मुझे एक पैकेज बनाने के लिए प्रोत्साहित किया जिसका आप उपयोग कर सकते हैं।

$ pip install read-only-properties

अपने अजगर के खोल में:

In [1]: from rop import read_only_properties

In [2]: @read_only_properties('a')
   ...: class Foo:
   ...:     def __init__(self, a, b):
   ...:         self.a = a
   ...:         self.b = b
   ...:         

In [3]: f=Foo('explodes', 'ok-to-overwrite')

In [4]: f.b = 5

In [5]: f.a = 'boom'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-a5226072b3b4> in <module>()
----> 1 f.a = 'boom'

/home/oznt/.virtualenvs/tracker/lib/python3.5/site-packages/rop.py in __setattr__(self, name, value)
    116                     pass
    117                 else:
--> 118                     raise AttributeError("Can't touch {}".format(name))
    119 
    120                 super().__setattr__(name, value)

AttributeError: Can't touch a

1
यह वास्तव में मददगार है, और वही करता है जो मैं करना चाहता था। धन्यवाद। हालाँकि, यह उन लोगों के लिए है जिनके पास पायथन 3 स्थापित है। मैं पायथॉन 2.7.8 का उपयोग कर रहा हूं, इसलिए मुझे आपके समाधान के लिए दो मामूली टिक्कों को लागू करना होगा: "क्लास न्यूक्लास (cls, <b> ऑब्जेक्ट <\ b>):" ... "<b> सुपर (न्यूक्लास, स्व) <\ b> .__ सेट्ट्र __ (नाम, मान) "।
यिंग झांग

1
इसके अलावा, किसी को वर्ग के सदस्य चरों और सूचियों के बारे में सावधान रहना चाहिए। आप वास्तव में इस तरह से अद्यतन होने से उन्हें 'बंद नहीं' कर सकते।
यिंग जांग

1
एक सुधार और तीन समस्याएं यहां। सुधार: if..elif..elseब्लॉक if name in attrs and name in self.__dict__: raise Attr...बिना किसी passआवश्यकता के साथ हो सकता है। समस्या 1: कक्षाएं इस प्रकार सभी एक समान के साथ समाप्त होती हैं __name__, और उनके प्रकार के स्ट्रिंग प्रतिनिधित्व को भी समरूप किया जाता है। समस्या 2: यह सजावट किसी भी प्रथा को अधिलेखित करती है __setattr__। समस्या 3: उपयोगकर्ता इसके साथ हार सकते हैं del MyClass.__setattr__
टाइगरहॉक 3

बस एक भाषा की बात। "काश ..." का अर्थ है "कहने के लिए दुःख, ..." जो आप नहीं चाहते हैं, मुझे लगता है।
थॉमस एंड्रयूज

मुझे कुछ भी करने से नहीं रोकेगा object.__setattr__(f, 'forbidden', 42)। मैं यह नहीं देखता कि read_only_propertiesडबल अंडरस्कोर नाम मैन्बलिंग द्वारा क्या नहीं जोड़ा जाता है।
L3viathan

4

यहाँ केवल पढ़ने के गुणों के लिए एक अलग दृष्टिकोण है, जिसे शायद लिखना-एक बार गुण कहा जाना चाहिए क्योंकि उन्हें आरंभिक रूप से प्राप्त करना है, क्या नहीं? हमारे बीच के व्यामोह के लिए, जो सीधे वस्तु के शब्दकोश तक पहुंचकर गुणों को संशोधित करने में सक्षम होने के बारे में चिंता करते हैं, मैंने "चरम" नाम का परिचय दिया है:

from uuid import uuid4

class Read_Only_Property:
    def __init__(self, name):
        self.name = name
        self.dict_name = uuid4().hex
        self.initialized = False

    def __get__(self, instance, cls):
        if instance is None:
            return self
        else:
            return instance.__dict__[self.dict_name]

    def __set__(self, instance, value):
        if self.initialized:
            raise AttributeError("Attempt to modify read-only property '%s'." % self.name)
        instance.__dict__[self.dict_name] = value
        self.initialized = True

class Point:
    x = Read_Only_Property('x')
    y = Read_Only_Property('y')
    def __init__(self, x, y):
        self.x = x
        self.y = y

if __name__ == '__main__':
    try:
        p = Point(2, 3)
        print(p.x, p.y)
        p.x = 9
    except Exception as e:
        print(e)

अच्छा लगा। यदि आप dict_nameइसके बजाय mangle करते हैं, जैसे dict_name = "_spam_" + nameकि यह निर्भरता को दूर करता है uuid4और डीबगिंग को बहुत आसान बनाता है।
cz

लेकिन फिर मैं p.__dict__['_spam_x'] = 5मान को बदलने के लिए कह सकता हूं p.x, इसलिए यह पर्याप्त नाम प्रबंधन नहीं है।
उल्लू

1

मैं केवल पढ़ने के गुणों को बनाने के लिए पिछले दो उत्तरों से असंतुष्ट हूं क्योंकि पहला समाधान आसानी से हटाए जाने की विशेषता देता है और फिर __dict__ को ब्लॉक नहीं करता है। दूसरे समाधान को परीक्षण के साथ चारों ओर काम किया जा सकता है - उस मूल्य को खोजना जो समान है जो आपने इसे दो सेट किया और अंततः इसे बदल दिया।

अब, कोड के लिए।

def final(cls):
    clss = cls
    @classmethod
    def __init_subclass__(cls, **kwargs):
        raise TypeError("type '{}' is not an acceptable base type".format(clss.__name__))
    cls.__init_subclass__ = __init_subclass__
    return cls


def methoddefiner(cls, method_name):
    for clss in cls.mro():
        try:
            getattr(clss, method_name)
            return clss
        except(AttributeError):
            pass
    return None


def readonlyattributes(*attrs):
    """Method to create readonly attributes in a class

    Use as a decorator for a class. This function takes in unlimited 
    string arguments for names of readonly attributes and returns a
    function to make the readonly attributes readonly. 

    The original class's __getattribute__, __setattr__, and __delattr__ methods
    are redefined so avoid defining those methods in the decorated class

    You may create setters and deleters for readonly attributes, however
    if they are overwritten by the subclass, they lose access to the readonly
    attributes. 

    Any method which sets or deletes a readonly attribute within
    the class loses access if overwritten by the subclass besides the __new__
    or __init__ constructors.

    This decorator doesn't support subclassing of these classes
    """
    def classrebuilder(cls):
        def __getattribute__(self, name):
            if name == '__dict__':
                    from types import MappingProxyType
                    return MappingProxyType(super(cls, self).__getattribute__('__dict__'))
            return super(cls, self).__getattribute__(name)
        def __setattr__(self, name, value): 
                if name == '__dict__' or name in attrs:
                    import inspect
                    stack = inspect.stack()
                    try:
                        the_class = stack[1][0].f_locals['self'].__class__
                    except(KeyError):
                        the_class = None
                    the_method = stack[1][0].f_code.co_name
                    if the_class != cls: 
                         if methoddefiner(type(self), the_method) != cls:
                            raise AttributeError("Cannot set readonly attribute '{}'".format(name))                        
                return super(cls, self).__setattr__(name, value)
        def __delattr__(self, name):                
                if name == '__dict__' or name in attrs:
                    import inspect
                    stack = inspect.stack()
                    try:
                        the_class = stack[1][0].f_locals['self'].__class__
                    except(KeyError):
                        the_class = None
                    the_method = stack[1][0].f_code.co_name
                    if the_class != cls:
                        if methoddefiner(type(self), the_method) != cls:
                            raise AttributeError("Cannot delete readonly attribute '{}'".format(name))                        
                return super(cls, self).__delattr__(name)
        clss = cls
        cls.__getattribute__ = __getattribute__
        cls.__setattr__ = __setattr__
        cls.__delattr__ = __delattr__
        #This line will be moved when this algorithm will be compatible with inheritance
        cls = final(cls)
        return cls
    return classrebuilder

def setreadonlyattributes(cls, *readonlyattrs):
    return readonlyattributes(*readonlyattrs)(cls)


if __name__ == '__main__':
    #test readonlyattributes only as an indpendent module
    @readonlyattributes('readonlyfield')
    class ReadonlyFieldClass(object):
        def __init__(self, a, b):
            #Prevent initalization of the internal, unmodified PrivateFieldClass
            #External PrivateFieldClass can be initalized
            self.readonlyfield = a
            self.publicfield = b


    attr = None
    def main():
        global attr
        pfi = ReadonlyFieldClass('forbidden', 'changable')
        ###---test publicfield, ensure its mutable---###
        try:
            #get publicfield
            print(pfi.publicfield)
            print('__getattribute__ works')
            #set publicfield
            pfi.publicfield = 'mutable'
            print('__setattr__ seems to work')
            #get previously set publicfield
            print(pfi.publicfield)
            print('__setattr__ definitely works')
            #delete publicfield
            del pfi.publicfield 
            print('__delattr__ seems to work')
            #get publicfield which was supposed to be deleted therefore should raise AttributeError
            print(pfi.publlicfield)
            #publicfield wasn't deleted, raise RuntimeError
            raise RuntimeError('__delattr__ doesn\'t work')
        except(AttributeError):
            print('__delattr__ works')


        try:
            ###---test readonly, make sure its readonly---###
            #get readonlyfield
            print(pfi.readonlyfield)
            print('__getattribute__ works')
            #set readonlyfield, should raise AttributeError
            pfi.readonlyfield = 'readonly'
            #apparently readonlyfield was set, notify user
            raise RuntimeError('__setattr__ doesn\'t work')
        except(AttributeError):
            print('__setattr__ seems to work')
            try:
                #ensure readonlyfield wasn't set
                print(pfi.readonlyfield)
                print('__setattr__ works')
                #delete readonlyfield
                del pfi.readonlyfield
                #readonlyfield was deleted, raise RuntimeError
                raise RuntimeError('__delattr__ doesn\'t work')
            except(AttributeError):
                print('__delattr__ works')
        try:
            print("Dict testing")
            print(pfi.__dict__, type(pfi.__dict__))
            attr = pfi.readonlyfield
            print(attr)
            print("__getattribute__ works")
            if pfi.readonlyfield != 'forbidden':
                print(pfi.readonlyfield)
                raise RuntimeError("__getattr__ doesn't work")
            try:
                pfi.__dict__ = {}
                raise RuntimeError("__setattr__ doesn't work")
            except(AttributeError):
                print("__setattr__ works")
            del pfi.__dict__
            raise RuntimeError("__delattr__ doesn't work")
        except(AttributeError):
            print(pfi.__dict__)
            print("__delattr__ works")
            print("Basic things work")


main()

आपके लेखन लाइब्रेरी कोड, कोड को छोड़कर केवल विशेषताओं को पढ़ने का कोई मतलब नहीं है , जो कोड को प्रोग्राम के रूप में उपयोग करने के लिए दूसरों को वितरित किया जा रहा है, न कि किसी अन्य उद्देश्य के लिए कोड, जैसे कि ऐप डेवलपमेंट। __Dict__ समस्या हल हो गई है, क्योंकि __dict__ अब अपरिवर्तनीय प्रकारों का है। मैपिंग ProxyType , इसलिए विशेषताओं को __dict__ के माध्यम से नहीं बदला जा सकता है। __Dict__ को सेट करना या हटाना भी अवरुद्ध है। केवल पढ़ने के गुणों को बदलने का एकमात्र तरीका कक्षा के तरीकों को बदलने के माध्यम से है।

हालांकि मेरा मानना ​​है कि मेरा समाधान पिछले दो की तुलना में बेहतर है, इसमें सुधार किया जा सकता है। ये इस कोड की कमजोरियां हैं:

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

ख) केवल पढ़ने के प्रतिबंधों को हराने के लिए कक्षा के पठनीय तरीकों को बदला जा सकता है।

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

अजगर में इसका जवाब कैसे अजगर में एक और वर्ग के एक समारोह के अंदर कॉलर वर्ग का नाम पाने के लिए? कॉलर कक्षाओं और विधियों को प्राप्त करने के लिए।


object.__setattr__(pfi, 'readonly', 'foobar')इस समाधान को तोड़ता है, बिना कक्षा को संपादित किए।
L3viathan

0

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

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


0

जबकि मुझे Oz123 का क्लास डेकोरेटर पसंद है, तो आप निम्न कार्य भी कर सकते हैं, जो एक स्पष्ट वर्ग आवरण और __new__ का उपयोग करता है जिसमें क्लास फैक्ट्री विधि एक बंद के भीतर कक्षा को वापस करती है:

class B(object):
    def __new__(cls, val):
        return cls.factory(val)

@classmethod
def factory(cls, val):
    private = {'var': 'test'}

    class InnerB(object):
        def __init__(self):
            self.variable = val
            pass

        @property
        def var(self):
            return private['var']

    return InnerB()

आपको यह दिखाते हुए कुछ परीक्षण जोड़ना चाहिए कि यह कई गुणों के साथ कैसे काम करता है
Oz123

0

यही मेरा काम है।

@property
def language(self):
    return self._language
@language.setter
def language(self, value):
    # WORKAROUND to get a "getter-only" behavior
    # set the value only if the attribute does not exist
    try:
        if self.language == value:
            pass
        print("WARNING: Cannot set attribute \'language\'.")
    except AttributeError:
        self._language = value

0

किसी ने एक छद्म वस्तु का उपयोग करते हुए उल्लेख किया, मुझे इसका उदाहरण नहीं दिखाई दिया, इसलिए मैंने इसे समाप्त करने की कोशिश की, [खराब]।

/! \ _ यदि संभव हो तो कक्षा की परिभाषाएँ और क्लास कंस्ट्रक्टर पसंद करें

यह कोड प्रभावी तरीके से class.__new__(क्लास कंस्ट्रक्टर) को फिर से लिखना है ताकि हर तरह से खराब हो। अपने आप को दर्द से बचाएं और यदि आप कर सकते हैं तो इस पैटर्न का उपयोग न करें।

def attr_proxy(obj):
    """ Use dynamic class definition to bind obj and proxy_attrs.
        If you can extend the target class constructor that is 
        cleaner, but its not always trivial to do so.
    """
    proxy_attrs = dict()

    class MyObjAttrProxy():
        def __getattr__(self, name):
            if name in proxy_attrs:
                return proxy_attrs[name]  # overloaded

            return getattr(obj, name)  # proxy

        def __setattr__(self, name, value):
            """ note, self is not bound when overloading methods
            """
            proxy_attrs[name] = value

    return MyObjAttrProxy()


myobj = attr_proxy(Object())
setattr(myobj, 'foo_str', 'foo')

def func_bind_obj_as_self(func, self):
    def _method(*args, **kwargs):
        return func(self, *args, **kwargs)
    return _method

def mymethod(self, foo_ct):
    """ self is not bound because we aren't using object __new__
        you can write the __setattr__ method to bind a self 
        argument, or declare your functions dynamically to bind in 
        a static object reference.
    """
    return self.foo_str + foo_ct

setattr(myobj, 'foo', func_bind_obj_as_self(mymethod, myobj))

-2

मुझे पता है कि मैं इस धागे को मृत से वापस ला रहा हूं, लेकिन मैं देख रहा था कि केवल पढ़ने के लिए एक संपत्ति कैसे बनाई जाए और इस विषय को खोजने के बाद, मैं पहले से ही साझा किए गए समाधानों से संतुष्ट नहीं था।

इसलिए, यदि आप इस कोड से शुरू करते हैं, तो प्रारंभिक प्रश्न पर वापस जाएं:

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

और आप एक्स को आसानी से बनाना चाहते हैं, आप बस जोड़ सकते हैं:

@x.setter
def x(self, value):
    raise Exception("Member readonly")

फिर, यदि आप निम्नलिखित चलाते हैं:

print (x) # Will print whatever X value is
x = 3 # Will raise exception "Member readonly"

3
लेकिन अगर आप सिर्फ एक सेटर नहीं बनाते हैं, तो असाइन करने की कोशिश करने पर एक त्रुटि हो जाएगी ( AttributeError('can't set attribute')
एएन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.