পাইথন-পঠনযোগ্য সম্পত্তি


97

বৈশিষ্ট্যটি কখন ব্যক্তিগত হবে এবং আমার সম্পত্তি ব্যবহার করা উচিত তা আমি জানি না।

আমি সম্প্রতি পড়েছি যে সেটার এবং গেটাররা পাইথোনিক নয় এবং আমার সম্পত্তি সজ্জা ব্যবহার করা উচিত। ঠিক আছে.

তবে আমার যদি অ্যাট্রিবিউট থাকে তবে তা অবশ্যই শ্রেণীর বাইরে থেকে সেট করা উচিত নয় তবে পড়তে পারা যায় (কেবলমাত্র পঠনযোগ্য বৈশিষ্ট্য)। এই বৈশিষ্ট্যটি কি ব্যক্তিগত হওয়া উচিত এবং গোপনে বলতে চাই আমার মতো আন্ডারস্কোর দিয়ে self._x? যদি হ্যাঁ হয় তবে আমি কীভাবে গেটর ব্যবহার না করে এটি পড়তে পারি? আমি এখনই জানি কেবল পদ্ধতিটিই লিখতে হয়

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

এইভাবে আমি গুণাবলী পড়তে পারি obj.xতবে আমি সেট করতে পারি না obj.x = 1তাই এটি ঠিক আছে।

তবে আমার কি এমন অবজেক্ট স্থাপন করা উচিত যা সেট করা উচিত নয়? আমার শুধু এটি ছেড়ে দেওয়া উচিত। তবে আবার আমি আন্ডারস্কোর ব্যবহার করতে পারি না কারণ obj._xব্যবহারকারীর পক্ষে পড়া অদ্ভুত, তাই আমার ব্যবহার করা উচিত obj.xএবং তারপরে আবার ব্যবহারকারী জানেন না যে তিনি এই বৈশিষ্ট্যটি সেট করবেন না।

আপনার মতামত এবং অনুশীলন কি?


4
কোনও সম্পত্তির ধারণাটি হ'ল এটি একটি গুনের মতো আচরণ করে তবে অতিরিক্ত কোড থাকতে পারে। আপনি যদি চান সমস্ত কিছু একটি মূল্য পেতে হয় তবে আমি বিরক্তও করব না: কেবল ব্যবহার করুন self.xএবং বিশ্বাস করুন যে কেউ পরিবর্তন করবে না x। যদি xএটি পরিবর্তন করা যায় না তা নিশ্চিত করা গুরুত্বপূর্ণ, তবে কোনও সম্পত্তি ব্যবহার করুন।
li.davidm

এছাড়াও, _xমোটেও অদ্ভুত নয়: কনভেনশন অনুসারে এর অর্থ কিছুটা "ব্যক্তিগত"।
li.davidm

4
আমি বোঝাতে চাইছি _x থেকে পড়া বিজোড়। _X নাম নিজেই নয়। ব্যবহারকারী যদি _x থেকে সরাসরি পড়ছেন তবে তিনি দায়িত্বজ্ঞানহীন।
রাফা łużyński

4
গুরুত্বপূর্ণ! আপনার ক্লাসটি অবশ্যই একটি নতুন-স্টাইলের ক্লাস হতে হবে অর্থাৎ উত্তরাধিকার সূত্রে প্রাপ্ত object, এটির জন্য আপনাকে প্রকৃতপক্ষে সেট করা বন্ধ করতে obj.x। পুরানো স্টাইলের ক্লাসে আপনি এখনও স্থির করতে পারেন obj.x, বেশ অপ্রত্যাশিত ফলাফল সহ।
ইয়ান এইচ এইচ

কেবলমাত্র পঠনযোগ্য বৈশিষ্ট্য থাকার বেশ কয়েকটি বৈধ কারণ রয়েছে। একটি যখন আপনার কাছে এমন একটি মান থাকে যা দুটি অন্যান্য (পড়ুন / লিখুন) মার্জ করে। আপনি এটি একটি পদ্ধতিতে করতে পারেন, তবে আপনি এটি কেবল পঠিত সম্পত্তিতেও করতে পারেন।
ফিলিওগন

উত্তর:


73

সাধারণত, পাইথন প্রোগ্রামগুলি এই ধারণাটি দিয়ে লেখা উচিত যে সমস্ত ব্যবহারকারীরা প্রাপ্তবয়স্কদের সম্মতি দিচ্ছেন এবং এইভাবে তারা সঠিকভাবে জিনিস ব্যবহারের জন্য দায়বদ্ধ। যাইহোক, বিরল উদাহরণে যেখানে কোনও বৈশিষ্ট্য স্থায়ী হওয়ার জন্য এটি কেবল অর্থবোধ করে না (যেমন উত্পন্ন মান, বা কোনও স্ট্যাটিক ডেটাসোর্স থেকে পড়া মান), কেবলমাত্র প্রাপ্তি সম্পত্তি সাধারণত পছন্দসই প্যাটার্ন।


26
দেখে মনে হচ্ছে আপনার উত্তর নিজের সাথে বিপরীত। আপনি বলছেন যে ব্যবহারকারীদের দায়িত্বশীল হওয়া উচিত এবং জিনিসগুলি সঠিকভাবে ব্যবহার করা উচিত, তারপরে আপনি বলে থাকেন যে কখনও কখনও এটি কোনও বৈশিষ্ট্যের জন্য স্থায়ী হওয়া এবং গেটের সম্পত্তিটি একটি প্রিফার্ড উপায় হিসাবে বোঝায় না। আমার মতে আপনি বৈশিষ্ট্য সেট করতে পারবেন না বা করতে পারবেন না। কেবলমাত্র প্রশ্নটি হল যদি আমার এই অ্যাটরিকে রক্ষা করা উচিত বা এটি ছেড়ে দেওয়া উচিত। এর মধ্যে কোনও উত্তর দেওয়া উচিত নয়।
রাফা łuŁyński

20
না, আমি বলেছিলাম যদি আপনি আক্ষরিক অর্থে কোনও মান সেট করতে না পারেন, তবে সেটার রাখার অর্থ হবে না। উদাহরণস্বরূপ, যদি আপনার ব্যাসার্ধের সদস্য সহ একটি বৃত্তের অবজেক্ট থাকে এবং ব্যাসার্ধ থেকে উদ্ভূত একটি পরিধি বৈশিষ্ট্য থাকে, বা আপনার এমন একটি অবজেক্ট রয়েছে যা কিছু পঠনযোগ্য রিয়েল-টাইম এপিআইকে বেশ কয়েকটি গেটর-কেবল বৈশিষ্ট্যগুলিতে আবৃত করে। কোনও কিছুর বিরোধিতা করছে না।
সিলাস রায়

9
তবে দায়বদ্ধ ব্যবহারকারীর এমন আত্তার সেট করার চেষ্টা করবেন না যা আক্ষরিকভাবে সেট করা যায় না। এবং আবার কোনও দায়বদ্ধ ব্যবহারকারী অ্যাটরিকে সেট করবেন না যে আক্ষরিকভাবে সেট করা যেতে পারে এবং তার সেটের কারণে কোডে অন্য কোথাও ত্রুটি বাড়িয়ে তুলবে। সুতরাং শেষ পর্যন্ত উভয় অ্যাটর্ই সেট করা যাবে না। আমি উভয় সম্পত্তি ব্যবহার করা উচিত বা এটি কোন ব্যবহার না?
রাফা łużyński

8
তবে দায়বদ্ধ ব্যবহারকারীর এমন অ্যাট্রি সেট করার চেষ্টা করা উচিত নয় যা আক্ষরিকভাবে সেট করা যায় না। প্রোগ্রামিংয়ে, যদি কোনও কিছু কঠোরভাবে একটি স্থাবর-অযোগ্য মান হয় তবে দায়বদ্ধ বা বুদ্ধিমান জিনিস হ'ল তা নিশ্চিত করা যায় না। এই ছোট জিনিসগুলি সমস্ত নির্ভরযোগ্য প্রোগ্রামগুলিতে অবদান রাখে।
রবিন স্মিথ

6
এটি অনেক লোক এবং ভাষা গ্রহণ করে। যদি এটি এমন অবস্থান হয় যা আপনি অ-আলোচনাযোগ্য মনে করেন তবে আপনার সম্ভবত পাইথন ব্যবহার করা উচিত নয়।
সিলাস রায়

75

শুধু আমার দুটি সেন্ট, সিলাস রায় সঠিক পথে আছে, তবে আমি উদাহরণ যোগ করার মতো অনুভব করেছি। ;-)

পাইথন হ'ল টাইপ-অনিরাপদ ভাষা এবং সুতরাং আপনাকে যুক্তিসঙ্গত (বোধগম্য) ব্যক্তির মতো কোডটি ব্যবহার করতে আপনার কোড ব্যবহারকারীদের সর্বদা বিশ্বাস করতে হবে।

প্রতি পিইপি 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
পাইথনটি নিরাপদ নয়, এটি গতিশীলভাবে টাইপ করা হয়েছে। এবং নাম ম্যাংলিংটি প্রতারণা করা আরও কঠিন করার জন্য নয়, তবে উত্তরাধিকার সমস্যা হতে পারে এমন পরিস্থিতিতে পরিস্থিতিতে নাম সংঘর্ষ প্রতিরোধ করা (আপনি যদি বড় প্রোগ্রামিং না করেন তবে আপনার যত্নও করা উচিত নয়)।
মেমপ্লেক্স

4
তবে আপনার এখনও মনে রাখা উচিত, যেভাবে যাইহোক এই পদ্ধতি ব্যবহার করে পরিবর্তনীয় অবজেক্টগুলি পরিবর্তন করা যেতে পারে। উদাহরণস্বরূপ যদি self.__a = [], আপনি এখনও এটি করতে পারেন a.a.append('anything')এবং এটি কার্যকর হবে।
ইগোর

4
"একটি যুক্তিসঙ্গত (বুদ্ধিমান)" ব্যক্তির এই উত্তরের বিষয়ে কী আছে তা আমার কাছে পরিষ্কার নয়। আপনি কি ভাবেন যে যুক্তিসঙ্গত ব্যক্তি করবেন এবং কী করবেন না সে ধরণের জিনিসগুলির বিষয়ে আপনি আরও স্পষ্ট থাকতে পারেন?
winni2k

4
আমার কাছে @ প্রপার্টি সজ্জাটি ব্যবহার করার জন্য, যখন আপনি এই উত্তরটি দেবেন পুরো বিষয়টি তখন আপনাকে অবজেক্ট থেকে উত্তরাধিকারী হতে হবে । ধন্যবাদ
আক্কি

4
@kkm কে কখনই কোডটিতে কোনও ত্রুটি ছুঁতে না দেওয়ার একমাত্র উপায় হ'ল কোডটি কখনই লেখা না।
আলেচান

58

ধারণাটি এড়াতে এখানে একটি উপায়

সমস্ত ব্যবহারকারীরা প্রাপ্তবয়স্কদের সম্মতি দিচ্ছেন এবং এইভাবে তারা নিজেরাই জিনিসগুলি সঠিকভাবে ব্যবহারের জন্য দায়বদ্ধ।

নীচে আমার আপডেট দেখুন

ব্যবহার @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

4
এটি সত্যই সহায়ক এবং আমি যা করতে চেয়েছিলাম ঠিক তা করে। ধন্যবাদ. তবে এটি তাদের জন্য যারা পাইথন 3 ইনস্টল করেছেন। আমি পাইথন ২.7.৮ ব্যবহার করছি, সুতরাং আপনার সমাধানে আমাকে দুটি ছোট ছোট টুইট প্রয়োগ করতে হবে: "ক্লাস নিউক্লাস (ক্লাস, <b> অবজেক্ট <b>):" ... "<b> সুপার (নিউ ক্লাস, স্ব) <\ b> .__ সেট্যাটর __ (নাম, মান) "।
ইং জাং

4
এছাড়াও, ক্লাস সদস্যের ভেরিয়েবলগুলি তালিকা এবং অভিধানের বিষয়ে সতর্ক হওয়া উচিত। আপনি এইভাবে আপডেট হওয়া থেকে সত্যই তাদের 'লক ডাউন' করতে পারবেন না।
ইং জাং

4
একটি উন্নতি এবং এখানে তিনটি সমস্যা। উন্নতি: if..elif..elseব্লকটি কেবল প্রয়োজন if name in attrs and name in self.__dict__: raise Attr...ছাড়া হতে পারে pass। সমস্যা 1: ক্লাসগুলি এইভাবে সমস্তকে অভিন্ন হিসাবে সজ্জিত করে __name__এবং তাদের ধরণের স্ট্রিং উপস্থাপনাটিও একত্রিত হয়। সমস্যা 2: এই সজ্জাটি কোনও কাস্টমকে ওভাররাইট করে __setattr__। সমস্যা 3: ব্যবহারকারীরা এটি দিয়ে পরাস্ত করতে পারেন del MyClass.__setattr__
টাইগারহকটি

শুধু একটি ভাষার জিনিস। "হায়রে ..." এর অর্থ "দুঃখের সাথে বলতে হবে, ..." যা আপনি চান তা নয়, আমি মনে করি।
থমাস অ্যান্ড্রুজ

কিছুই আমাকে করতে বাধা দেবে না 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পরিবর্তে ম্যাঙ্গেল করেন , উদাহরণস্বরূপ dict_name = "_spam_" + nameএটি এর উপর নির্ভরতা সরিয়ে দেয় uuid4এবং ডিবাগিংকে অনেক সহজ করে তোলে।
সিজেড

তবে তারপরে আমি 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__ নির্ধারণ বা মোছার বিষয়টিও অবরুদ্ধ। কেবলমাত্র পঠিত বৈশিষ্ট্যগুলি পরিবর্তনের একমাত্র উপায় হ'ল শ্রেণীর নিজস্ব পদ্ধতি পরিবর্তনের মাধ্যমে।

যদিও আমি বিশ্বাস করি আমার সমাধানটি আগের দুটির চেয়ে ভাল তবে এটি উন্নত হতে পারে। এগুলি এই কোডের দুর্বলতা:

ক) সাবক্লাসে এমন কোনও পদ্ধতির সাথে যুক্ত হওয়ার অনুমতি দেয় না যা কেবল পাঠযোগ্য বৈশিষ্ট্য সেট করে বা মুছে দেয়। সাবক্লাসে সংজ্ঞায়িত একটি পদ্ধতি স্বয়ংক্রিয়ভাবে পদ্ধতির সুপারক্লাসের সংস্করণে কল করে একটি পঠনযোগ্য বৈশিষ্ট্য অ্যাক্সেস থেকে স্বয়ংক্রিয়ভাবে নিষিদ্ধ।

খ) কেবল পাঠের সীমাবদ্ধতাকে পরাস্ত করতে শ্রেণীর 'পঠনযোগ্য পদ্ধতিগুলি পরিবর্তন করা যেতে পারে।

তবে কেবলমাত্র পঠনযোগ্য বৈশিষ্ট্য সেট করতে বা মুছতে ক্লাস সম্পাদনা ছাড়া উপায় নেই। এটি নামকরণের কনভেনশনগুলির উপর নির্ভর করে না, যা ভাল কারণ পাইথন নামকরণ কনভেনশনগুলির সাথে এতটা সুসংগত নয়। এটি কেবল পঠিত বৈশিষ্ট্যগুলি তৈরি করার একটি উপায় সরবরাহ করে যা ক্লাসে নিজেই সম্পাদনা না করে লুকানো ফাঁক দিয়ে পরিবর্তন করা যায় না। সাজসজ্জারকে আর্গুমেন্ট হিসাবে কল করার সময় কেবল পাঠযোগ্য গুণাবলী তালিকাভুক্ত করুন এবং সেগুলি কেবল পঠনযোগ্য হয়ে উঠবে।

ব্রাইসের উত্তরের কৃতিত্ব কীভাবে পাইথনটিতে অন্য শ্রেণির কোনও ফাংশনের ভিতরে কলার শ্রেণির নাম পাবেন? কলার ক্লাস এবং পদ্ধতি পাওয়ার জন্য।


object.__setattr__(pfi, 'readonly', 'foobar')ক্লাসটি নিজেই সম্পাদনা না করেই এই সমাধানটি ভেঙে দেয়।
L3viathan

0

লক্ষ্য করুন যে উদাহরণের পদ্ধতিগুলিও (শ্রেণীর) বৈশিষ্ট্য এবং আপনি যদি সত্যই খারাপ হতে চান তবে আপনি সেগুলি শ্রেণি বা উদাহরণ স্তরে স্থাপন করতে পারেন। অথবা আপনি একটি শ্রেণীর ভেরিয়েবল সেট করতে পারেন (এটি ক্লাসের একটি বৈশিষ্ট্যও), যেখানে সহজেই পঠনযোগ্য বৈশিষ্ট্যগুলি বাক্সের বাইরে খুব সুন্দরভাবে কাজ করবে না। আমি যা বলার চেষ্টা করছি তা হ'ল "পঠনযোগ্য গুণাবলী" সমস্যাটি আসলে সাধারণ হিসাবে অনুধাবনের চেয়ে বেশি সাধারণ। ভাগ্যক্রমে কাজের প্রচলিত প্রত্যাশাগুলি রয়েছে যা আমাদের অন্যান্য অন্ধকারে অন্ধ করতে এতটাই শক্তিশালী (সর্বোপরি, প্রায় সমস্ত কিছুই পাইথনের এক ধরণের বৈশিষ্ট্য)।

এই প্রত্যাশাগুলির ভিত্তিতে আমি মনে করি সবচেয়ে সাধারণ এবং লাইটওয়েট পদ্ধতির হ'ল কনভেনশনটি গ্রহণ করা যা "জনসাধারণ" (কোনও শীর্ষস্থানীয় আন্ডারস্কোর) বৈশিষ্ট্যগুলি কেবলমাত্র লেখার মতো স্পষ্টভাবে নথিভুক্ত করা ব্যতীত পঠনযোগ্য are এটি স্বাভাবিক প্রত্যাশা পূরণ করে যে পদ্ধতিগুলি প্যাচ করা হবে না এবং ক্লাস ভেরিয়েবলগুলি উদাহরণস্বরূপ ডিফল্টগুলি ইঙ্গিত করে আরও ভাল ছেড়ে দেওয়া উচিত। যদি আপনি কিছু বিশেষ গুণাবলী সম্পর্কে সত্যই ভৌতিক অনুভব করেন তবে সর্বশেষ উত্সের পরিমাপ হিসাবে একটি পঠনযোগ্য বিবরণী ব্যবহার করুন।


0

যদিও আমি ওজ 123 এর ক্লাস ডেকরেটার পছন্দ করি, আপনি নিম্নলিখিতগুলিও করতে পারেন, যা ক্লাস ফ্যাক্টরি পদ্ধতিতে ক্লোজ ফ্যাক্টরি পদ্ধতিতে ক্লাসের মধ্যে ক্লাস ফিরিয়ে দেওয়ার সাথে একটি স্পষ্ট শ্রেণীর মোড়ক ব্যবহার করে এবং __ নতুন __

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

প্রক্সি অবজেক্টটি ব্যবহার করে কেউ উল্লেখ করেছেন, আমি এর উদাহরণ দেখতে পেলাম না তাই চেষ্টা করে শেষ করেছি, [দুর্বল]।

/! Possible যদি সম্ভব হয় তবে শ্রেণীর সংজ্ঞা এবং শ্রেণি নির্মাতাদের পছন্দ করুন

এই কোডটি কার্যকরভাবে পুনরায় লেখার 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"

4
তবে আপনি যদি কেবল কোনও সেটার তৈরি না করেন, বরাদ্দ দেওয়ার চেষ্টা করা ত্রুটিও বাড়িয়ে তুলবে (আন AttributeError('can't set attribute')
ত্রুটিও বাড়বে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.