python - @Property ব্যবহার করে getters এবং setters বনাম




properties getter-setter (8)

এখানে একটি বিশুদ্ধ পাইথন নির্দিষ্ট নকশা প্রশ্ন:

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

    def set_my_attr(self, value):
        ...

এবং

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

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

পাইথন আমাদের যেকোন উপায়ে এটি করতে দেয়। আপনি যদি কোন পাইথন প্রোগ্রাম ডিজাইন করেন তবে কোন পদ্ধতিটি ব্যবহার করবেন এবং কেন?


[ টিএল; ডিআর? আপনি একটি কোড উদাহরণের জন্য শেষ করতে পারেন।]

আমি আসলে একটি ভিন্ন idiom ব্যবহার করতে পছন্দ করি, এটি একটি বন্ধ হিসাবে ব্যবহার করার জন্য একটু সামঞ্জস্যপূর্ণ, তবে যদি আপনার আরো জটিল ব্যবহারের ক্ষেত্রে ভাল হয়।

প্রথম পটভূমি একটি বিট।

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

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

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

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

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

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

    def defaultX(self):
        return someDefaultComputationForX()

    def defaultY(self):
        return someDefaultComputationForY()

আপনি অবাক defaultX কেন আমি defaultY defaultX এবং defaultY বস্তুর __init__ পদ্ধতিতে কল করি নি। কারণটি হল আমাদের ক্ষেত্রে আমি অনুমান করতে চাই যে কিছু someDefaultComputation পদ্ধতিগুলি সময়ের সাথে পরিবর্তিত মানের ফেরত দেয়, টাইমস্ট্যাম্প বলুন এবং যখনই x (বা y ) সেট না থাকে (যেখানে, এই উদাহরণের উদ্দেশ্যে "সেট না করা" মানে "কোনটিতে সেট করুন") আমি x এর (বা y গুলি) ডিফল্ট গণনা মান চাই।

তাই এই উপরে বর্ণিত কারণের জন্য লোম হয়। আমি বৈশিষ্ট্য ব্যবহার করে এটি পুনরায় লিখতে হবে:

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

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

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

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

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

    # default{XY} as before.

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

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

কিন্তু আমরা কি হারাই, আর আমরা কি করতে পারি না?

আমার দৃশ্যে প্রধান বিরক্তি হল যে, আপনি যদি কোন গেটর সংজ্ঞায়িত করেন (যেমন আমরা এখানে করি) তখন আপনাকে একটি সেট্টার সংজ্ঞায়িত করতে হবে। [1] যে অতিরিক্ত শব্দ যে কোড clutters।

আরেকটি বিরক্তি হল যে আমরা এখনও __init__x এবং y মানগুলি আরম্ভ করতে হবে। (আচ্ছা, অবশ্যই আমরা setattr() ব্যবহার করে তাদের যোগ করতে পারতাম কিন্তু এটি অতিরিক্ত কোড।)

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

আমরা ভালো কিছু করতে পারলে ভালো হবে:

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

উদাহরণ স্বরূপ. আমরা নিকটতমটি পেতে পারি অ্যাসাইনমেন্টটি কিছু বিশেষ সেম্যান্টিক্স বোঝাতে:

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

এবং নিশ্চিতভাবে আমাদের সেটারটি কীভাবে অভিধানের কী হিসাবে প্রথম তিনটি মান বের করতে হয় এবং একটি সংখ্যা বা কিছুতে তার মান সেট করে তা নিশ্চিত করে।

কিন্তু আমরা যদি তা করি তবে আমরা এখনও বৈশিষ্ট্যগুলির সাথে এটি সমর্থন করতে পারিনি কারণ মানটি পেতে কোনও উপায় নেই কারণ আমরা গেটটারের কাছে পরামিতিগুলি পাস করতে পারছি না। সুতরাং আমরা সবকিছু ফিরে ছিল, একটি বৈষম্য প্রবর্তন।

জাভা-স্টাইল গেট্টার / সেটার আমাদেরকে এইটিকে হ্যান্ডেল করতে দেয়, কিন্তু আমরা ফিরে গেটার / সেট্টারগুলির প্রয়োজন বোধ করি।

আমার মনে কি আমরা সত্যিই চাই যে নিম্নলিখিত প্রয়োজনীয়তা ক্যাপচার:

  • ব্যবহারকারীরা প্রদত্ত বৈশিষ্ট্যটির জন্য কেবলমাত্র একটি পদ্ধতি সংজ্ঞায়িত করে এবং এটিকে কেবল-পঠনযোগ্য বা পঠনযোগ্য-লেখার জন্য নির্দেশ করতে পারে। বৈশিষ্ট্য লেখার যোগ্য যদি এই পরীক্ষা ব্যর্থ।

  • ফাংশনের অন্তর্গত ব্যবহারকারীকে অতিরিক্ত পরিবর্তনশীল সংজ্ঞায়িত করার কোন প্রয়োজন নেই, তাই আমাদের __init__ বা setattr প্রয়োজন নেই। পরিবর্তনশীল শুধু আমরা এই নতুন স্টাইল বৈশিষ্ট্য তৈরি করেছেন দ্বারা বিদ্যমান।

  • বৈশিষ্ট্যটির জন্য কোনও ডিফল্ট কোড পদ্ধতির শরীরের মধ্যে সঞ্চালিত হয়।

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

  • আমরা বৈশিষ্ট্য পরামিতি করতে পারেন।

কোডের পরিপ্রেক্ষিতে, আমরা লিখতে একটি উপায় চাই:

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

এবং তারপর করতে সক্ষম হবেন:

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

এবং তাই ঘোষণা।

আমরা একটি পরামিতিযোগ্য বৈশিষ্ট্য বিশেষ ক্ষেত্রে এটি করার জন্য একটি উপায় চাই, তবে ডিফল্ট অ্যাসাইন কেসটি কাজ করার অনুমতি দেয়। আপনি নীচের এই মোকাবেলা কিভাবে দেখতে পাবেন।

এখন বিন্দু (হ্যাঁ! বিন্দু!)। নিম্নরূপ এই জন্য আমি সমাধান এসেছেন।

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

চলুন এটি একটি UberProperty কল।

class UberProperty(object):

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

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

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

আমি এখানে method অনুমান করা হল একটি ক্লাস পদ্ধতি, value UberProperty এর মান এবং আমি isSet যোগ isSet কারণ None প্রকৃত মান হতে পারে না এবং এটি আমাদেরকে "কোনও মান" বলে ঘোষণা করার একটি পরিচ্ছন্ন উপায় দেয় না। আরেকটি উপায় কিছু সাজানোর একটি ছদ্মবেশ।

এটি মূলত আমাদের এমন একটি বস্তু দেয় যা আমরা যা করতে চাই তা করতে পারে, কিন্তু আসলে আমরা কীভাবে আমাদের ক্লাসে রাখি? ভাল, বৈশিষ্ট্য decorators ব্যবহার করুন; কেন আমরা পারি না? দেখা যাক কিভাবে এটি দেখতে পারে (এখানে থেকে আমি শুধুমাত্র একটি 'গুণ' ব্যবহার করে আটকে যাচ্ছি, x )।

class Example(object):

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

এটি আসলে অবশ্যই কাজ করে না। আমাদের uberProperty বাস্তবায়ন করতে হবে এবং এটি উভয় পায় এবং সেট হ্যান্ডেল নিশ্চিত করুন।

এর সাথে শুরু করা যাক।

আমার প্রথম প্রচেষ্টা কেবল একটি নতুন UberProperty অবজেক্ট তৈরি এবং এটি ফেরত ছিল:

def uberProperty(f):
    return UberProperty(f)

আমি দ্রুত আবিষ্কার করেছিলাম যে, এটি কাজ করে না: পাইথন বস্তুকে কলযোগ্য বলে মনে করেন না এবং ফাংশনটি কল করার জন্য আমার বস্তুর প্রয়োজন। এমনকি শ্রেণীতে সজ্জা তৈরির কাজও কাজ করে না, যদিও এখন আমাদের শ্রেণী আছে, তবুও আমাদের সাথে কাজ করার জন্য কোনও অবজেক্ট নেই।

সুতরাং আমরা এখানে আরো করতে সক্ষম হতে হবে। আমরা জানি যে একটি পদ্ধতি শুধুমাত্র এক সময় প্রতিনিধিত্ব করতে হবে, তাই চলুন এগিয়ে যান এবং আমাদের সজ্জাকারীকে রাখুন, কিন্তু কেবল method রেফারেন্স সংরক্ষণ করার জন্য UberProperty পরিবর্তন করুন:

class UberProperty(object):

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

এটি কলযোগ্য নয়, তাই মুহূর্তে কিছুই কাজ করছে না।

আমরা কিভাবে ছবিটি সম্পূর্ণ করব? আচ্ছা, আমরা যখন আমাদের নতুন শোভাকর ব্যবহার করে উদাহরণ ক্লাস তৈরি করি তখন কী শেষ হয়:

class Example(object):

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

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

উভয় ক্ষেত্রেই আমরা UberProperty ফিরিয়ে UberProperty যা অবশ্যই একটি কলযোগ্য নয়, তাই এটি অনেক বেশি ব্যবহার নয়।

আমাদের যা দরকার তা হল ব্যবহারকারীর ব্যবহারের জন্য সেই অবজেক্টটি ফেরত দেওয়ার আগে ক্লাসের একটি বস্তুর ক্লাস তৈরি করার পরে সজ্জাকারী দ্বারা তৈরি UberProperty ইনস্ট্যান্সটি গতিশীলভাবে যুক্ত করার উপায়। উম, হ্যাঁ, এটি একটি __init__ কল, ড্যুড।

আসুন আমরা আমাদের অনুসন্ধান ফলাফল প্রথম হতে চান কি লিখুন। আমরা একটি UberProperty একটি UberProperty বাঁধাই করছি, তাই ফিরে একটি সুস্পষ্ট জিনিস একটি BoundUberProperty হবে। এই যেখানে আমরা আসলে x বৈশিষ্ট্য জন্য রাষ্ট্র বজায় রাখা হবে।

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

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

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

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

এখন আমরা উপস্থাপনা; কিভাবে একটি বস্তুর উপর এই পেতে না? কয়েকটি পন্থা আছে তবে ব্যাখ্যা করার সহজতম __init__ কেবলমাত্র __init__ পদ্ধতিটি ম্যাপিং করার জন্য ব্যবহার করে। __init__ দ্বারা আমাদের সজ্জাকারীদের চালানো হয়েছে বলে মনে করা হয়, তাই কেবলমাত্র বস্তুর __dict__ এর মাধ্যমে সন্ধান করতে হবে এবং এমন বৈশিষ্ট্যগুলি আপডেট করতে হবে যেখানে বৈশিষ্ট্যটির মান UberProperty

এখন, uber-properties cool এবং আমরা সম্ভবত তাদের অনেকগুলি ব্যবহার করতে চাই, সুতরাং এটি কেবল একটি বেস বর্গ তৈরি করতে ধার্য করে যা এটি সমস্ত উপশ্রেণীগুলির জন্য এটি করে। আমি আপনাকে বেস ক্লাস বলা হবে কি জানি।

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

আমরা এই যুক্ত, UberObject থেকে উত্তরাধিকারী আমাদের উদাহরণ পরিবর্তন, এবং ...

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

x পরিবর্তন করার পরে:

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

আমরা একটি সহজ পরীক্ষা চালাতে পারেন:

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

এবং আমরা আউটপুট আমরা চেয়েছিলেন পেতে:

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

(জি, আমি দেরিতে কাজ করছি।)

মনে রাখবেন যে আমি getValue , setValue এবং clearValue ব্যবহার getValue । এই কারণ আমি এখনও স্বয়ংক্রিয়ভাবে ফিরে এই উপায় লিঙ্ক না।

কিন্তু আমি এখন এই জন্য বন্ধ করার জন্য একটি ভাল জায়গা মনে করি, কারণ আমি ক্লান্ত হয়ে যাচ্ছি। আপনি দেখতে পারেন যে মূল কার্যকারিতাটি আমরা চেয়েছি; বাকি উইন্ডো ড্রেসিং হয়। গুরুত্বপূর্ণ ব্যবহারযোগ্য উইন্ডো ড্রেসিং, কিন্তু পোস্টটি হালনাগাদ করার পরিবর্তে এটি অপেক্ষা করতে পারে।

আমি এই বিষয়গুলি সংশোধন করে পরবর্তী পোস্টে উদাহরণটি শেষ করব:

  • আমাদের অবশ্যই নিশ্চিত করতে হবে যে UberObject এর __init__ সর্বদা উপশ্রেণীগুলির দ্বারা বলা হয়।

    • সুতরাং আমরা হয় কোথাও বলা যেতে পারে বা আমরা প্রয়োগ করা থেকে এটি প্রতিরোধ।
    • আমরা কিভাবে একটি metaclass সঙ্গে এটি দেখতে হবে।
  • আমাদের নিশ্চিত করা দরকার যে আমরা সাধারণ ক্ষেত্রে হ্যান্ডেল করি যেখানে কেউ 'উপাধি' অন্য কিছুতে একটি ফাংশন ব্যবহার করে, যেমন:

      class Example(object):
          @uberProperty
          def x(self):
              ...
    
          y = x
  • আমরা exgetValue() ডিফল্টরূপে ফেরত exgetValue() ex প্রয়োজন।

    • আমরা আসলে দেখতে পাবেন এই মডেলটি যেখানে একটি মডেল ব্যর্থ হয়।
    • এটি সক্রিয় করে আমরা মানটি পেতে সর্বদা একটি ফাংশন কল ব্যবহার করতে হবে।
    • কিন্তু আমরা এটি একটি নিয়মিত ফাংশন কল মত দেখতে এবং exgetValue() ব্যবহার করতে এড়াতে পারেন। (যদি আপনি এটি ইতিমধ্যে ঠিক না করে থাকেন তবে এটি করা এক সুস্পষ্ট।)
  • আমরা ex = <newvalue> যেমন সেটিং ex directly সমর্থন করতে হবে। আমরা পিতামাতার __init__ এটি করতে পারি, তবে এটি পরিচালনা করতে আমাদের __init__ কোডটি আপডেট করতে হবে।

  • অবশেষে, আমরা পরামিতি বৈশিষ্ট্য যোগ করব। এটা খুব স্পষ্ট হওয়া উচিত কিভাবে আমরা এই কাজ করব।

এই কোডটি এখন পর্যন্ত বিদ্যমান রয়েছে:

import datetime

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

    def uberGetter(self):
        return self

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


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

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

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

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

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

    def uberProperty(f):
        return UberProperty(f)

class Example(UberObject):

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

[1] আমি এখনও এই ক্ষেত্রে কিনা পিছনে হতে পারে।


আমার মনে হয় যে বৈশিষ্ট্যগুলি যখন আপনি প্রকৃতপক্ষে তাদের দরকার তখন শুধুমাত্র লেখক এবং সেট্টারগুলির উপরে ওভারহেড পেতে আপনাকে দেয়।

জাভা প্রোগ্রামিং সংস্কৃতি দৃঢ়ভাবে পরামর্শ দেয় যে এটি কখনই বৈশিষ্ট্যগুলিতে অ্যাক্সেস দেয় না এবং পরিবর্তে, গেটস এবং সেট্টারগুলির মধ্য দিয়ে যায় এবং কেবলমাত্র যা দরকার তা। কোডের এই স্পষ্ট টুকরাগুলি সবসময় লেখার জন্য এটি একটি বিট ক্রিয়াপদ এবং এটি লক্ষ্য করে যে 70% সময় কখনও তারা কিছু অ-তুচ্ছ যুক্তি দ্বারা প্রতিস্থাপিত হয় না।

পাইথন ইন, মানুষ আসলে এই ধরনের overhead জন্য যত্ন, যাতে আপনি নিম্নলিখিত অনুশীলন আলিঙ্গন করতে পারেন:

  • প্রথমে প্রয়োজন না হলে, getters এবং setters ব্যবহার করবেন না
  • আপনার বাকি কোডের সিনট্যাক্স পরিবর্তন না করেই তাদের প্রয়োগ করার জন্য @property ব্যবহার করুন।

আমি উভয় তাদের জায়গা আছে মনে। @property ব্যবহার করে এক সমস্যা হল স্ট্যান্ডার্ড ক্লাস মেকানিজমের সাহায্যে উপশ্রেণীগুলিতে @property বা @property আচরণ প্রসারিত করা কঠিন। সমস্যাটি প্রকৃত গেট্টার / সেটার ফাংশনগুলির সম্পত্তি লুকানো থাকে।

আপনি আসলে ফাংশন ধরে রাখতে পারেন, যেমন

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

আপনি Cpfget এবং Cpfset হিসাবে Cpfget এবং সেটার ফাংশন অ্যাক্সেস করতে পারেন, তবে আপনি সহজে স্বাভাবিক পদ্ধতির উত্তরাধিকার (যেমন সুপার) সুবিধাগুলি তাদের প্রসারিত করতে ব্যবহার করতে পারবেন না। কিছু সুপার এর intricacies মধ্যে খনন পরে, আপনি প্রকৃতপক্ষে এই ভাবে সুপার ব্যবহার করতে পারেন :

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

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

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

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

সুপার () ব্যবহার করা হয় তবে, বেশ কিছুটা সংকীর্ণ, যেহেতু সম্পত্তিটিকে পুনরায় সংজ্ঞায়িত করতে হবে, এবং আপনাকে পিটির আনবাউন্ড অনুলিপি পেতে সামান্য কাউন্টার-ইনুইভিটিভ সুপার (ক্লস, ক্লস) পদ্ধতি ব্যবহার করতে হবে।


আমি বেশিরভাগ ক্ষেত্রেই ব্যবহার করতে পছন্দ করি না। বৈশিষ্ট্য সঙ্গে সমস্যা হল যে তারা বর্গ কম স্বচ্ছ। বিশেষ করে, আপনি যদি একটি সেটটার থেকে ব্যতিক্রম বাড়াতে থাকেন তবে এটি একটি সমস্যা। উদাহরণস্বরূপ, যদি আপনার একটি অ্যাকাউন্ট.মেইল সম্পত্তি থাকে:

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

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

তারপরে শ্রেণির ব্যবহারকারী আশা করে না যে সম্পত্তিটির মান নির্ধারণ করলে ব্যতিক্রম হতে পারে:

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

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

আমি getters এবং setters ব্যবহার এড়াতে হবে:

  • অগ্রিম সব বৈশিষ্ট্য জন্য তাদের সংজ্ঞায়িত কারণ খুব সময় গ্রাসকারী হয়,
  • কোডটি অপ্রয়োজনীয়ভাবে লম্বা করে তোলে, যা বোঝার এবং কোডটিকে আরও কঠিন করে তোলে,
  • যদি আপনি শুধুমাত্র প্রয়োজনীয় হিসাবে বৈশিষ্ট্যের জন্য তাদের সংজ্ঞায়িত করেন, ক্লাসের ইন্টারফেসটি ক্লাসের সকল ব্যবহারকারীকে ক্ষতিগ্রস্ত করবে, পরিবর্তন হবে

পরিবর্তে বৈশিষ্ট্য এবং getters / setters আমি একটি বৈধকরণ পদ্ধতিতে যেমন ভাল সংজ্ঞায়িত জায়গায় জটিল যৌক্তিক করতে পছন্দ করে:

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

অথবা একটি অনুরূপ Account.save পদ্ধতি।

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


জটিল প্রকল্পগুলিতে আমি স্পষ্ট সেট্টার ফাংশনের সাথে শুধুমাত্র-পঠনযোগ্য বৈশিষ্ট্যগুলি ব্যবহার করতে পছন্দ করি (বা পেতে)

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

def set_my_attr(self, value):
    ...

দীর্ঘ জীবন্ত প্রকল্পগুলিতে ডিবাগিং এবং রিফ্যাক্টর কোডটি লেখার চেয়ে বেশি সময় নেয়। @property.setter Property.setter ব্যবহার করার জন্য কয়েকটি ডাউনসাইড রয়েছে যা ডিবাগিংকে আরও কঠিন করে তোলে:

1) পাইথন একটি বিদ্যমান বস্তুর জন্য নতুন গুণাবলী তৈরি করতে পারবেন। এটি ট্র্যাক করার জন্য নিচের একটি ভুল ছাপ তৈরি করে:

my_object.my_atttr = 4.

যদি আপনার বস্তুটি একটি জটিল অ্যালগরিদম হয় তবে আপনি কেন এটি একত্রিত করবেন না তা আবিষ্কার করার জন্য বেশ কিছু সময় ব্যয় করবেন (উপরের লাইনটিতে একটি অতিরিক্ত 'টি' লক্ষ্য করুন)

2) মাঝেমধ্যে সেট্টারটি জটিল এবং ধীর পদ্ধতির (যেমন ডেটাবেসকে হিট করা) হতে পারে। নিম্নলিখিত ফাংশন খুব ধীরে ধীরে কেন অন্য ডেভেলপারের জন্য এটি কঠিন হতে পারে। তিনি do_something() পদ্ধতি প্রোফাইল করার সময় অনেক সময় ব্যয় করতে পারেন, যখন my_object.my_attr = 4. আসলে মন্থর কারণ:

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

পাইথনটিতে আপনি শুধু মজার জন্য গেটস বা সেট্টার বা বৈশিষ্ট্য ব্যবহার করেন না। আপনি প্রথমে বৈশিষ্ট্যাবলী ব্যবহার করুন এবং তারপরে পরে শুধুমাত্র প্রয়োজন হলে, আপনার ক্লাসগুলি ব্যবহার করে কোডটি পরিবর্তন না করে অবশেষে কোনও সম্পত্তিতে স্থানান্তরিত হন।

প্রকৃতপক্ষে এক্সটেনশন সহ অনেক কোড রয়েছে .পিপি যা গেটারস এবং সেট্টারস এবং উত্তরাধিকার এবং বিন্দুহীন সব জায়গায় ব্যবহার করে যেখানে একটি সাধারণ টিপল কাজ করবে, তবে এটি পিওথন ব্যবহার করে C ++ বা জাভাতে লেখা ব্যক্তিদের কোড।

এটা পাইথন কোড নয়।



সংক্ষিপ্ত উত্তর হল: বৈশিষ্ট্য হাত নিচে জয় । সর্বদা.

কখনও কখনও গেটস এবং setters জন্য একটি প্রয়োজন, কিন্তু তারপরও, আমি বাইরের বিশ্বের তাদের "গোপন" হবে। Python এ এটি করার প্রচুর উপায় আছে ( getattr , setattr , __getattribute__ , ইত্যাদি ..., কিন্তু একটি খুব সংক্ষিপ্ত এবং পরিষ্কার একটি:

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

def get_email(self):
    return self._email

email = property(get_email, set_email)

এখানে একটি সংক্ষিপ্ত নিবন্ধ যা পাইথন এ গেটস এবং সেট্টারের বিষয় উপস্থাপন করে।





getter-setter