গেটর এবং সেটটারগুলি ব্যবহার করার অজগর উপায় কী?


340

আমি এটি এর মতো করছি:

def set_property(property,value):  
def get_property(property):  

অথবা

object.property = value  
value = object.property

আমি পাইথনে নতুন, তাই আমি এখনও বাক্যবিন্যাসটি অন্বেষণ করছি এবং আমি এটি করার জন্য কিছু পরামর্শ চাই।

উত্তর:


684

এটি চেষ্টা করুন: পাইথন সম্পত্তি

নমুনা কোডটি হ'ল:

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

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

    @x.setter
    def x(self, value):
        print("setter of x called")
        self._x = value

    @x.deleter
    def x(self):
        print("deleter of x called")
        del self._x


c = C()
c.x = 'foo'  # setter called
foo = c.x    # getter called
del c.x      # deleter called

2
Xx তাত্ক্ষণিককরণের সময় কি x এর সেটারটিকে ইনিশিয়ালাইজারে ডাকা হয়?
কেসি

7
@ ক্যাসি: নং এর উল্লেখ ._x(যা কোনও সম্পত্তি নয়, কেবল একটি সরল বৈশিষ্ট্য) propertyমোড়কে বাইপাস করে । কেবলমাত্র রেফারেন্সগুলিতে .xযেতে হবে property
শ্যাডোর্যাঞ্জার

275

গেটর এবং সেটটারগুলি ব্যবহার করার অজগর উপায় কী?

"পাইথোনিক" উপায়টি "গেটার্স" এবং "সেটটার" ব্যবহার করা নয় , বরং প্রশ্নটি যেমন প্রকাশ করে এবং delমুছে ফেলার মতো সরল বৈশিষ্ট্যগুলি ব্যবহার করে (তবে নামগুলি নির্দোষ ... বিল্টিনগুলি রক্ষা করতে পরিবর্তিত হয়):

value = 'something'

obj.attribute = value  
value = obj.attribute
del obj.attribute

যদি পরে, আপনি সেটিংসটি পরিবর্তন করতে এবং পেতে চান, আপনি ডেকরেটার ব্যবহার করে ব্যবহারকারীর কোড পরিবর্তন না করে এটি করতে পারেন property:

class Obj:
    """property demo"""
    #
    @property            # first decorate the getter method
    def attribute(self): # This getter method name is *the* name
        return self._attribute
    #
    @attribute.setter    # the property decorates with `.setter` now
    def attribute(self, value):   # name, e.g. "attribute", is the same
        self._attribute = value   # the "value" name isn't special
    #
    @attribute.deleter     # decorate with `.deleter`
    def attribute(self):   # again, the method name is the same
        del self._attribute

(প্রতিটি সাজসজ্জার ব্যবহার পূর্ববর্তী সম্পত্তি বস্তুর অনুলিপি এবং আপডেট করে, সুতরাং নোট করুন যে আপনার প্রতিটি সেটের জন্য একই নামটি ব্যবহার করা উচিত, ফাংশন / পদ্ধতিটি মুছুন এবং মুছুন।

উপরোক্ত সংজ্ঞা দেওয়ার পরে, কোডটি মুছে ফেলা এবং সেটিংস মুছে ফেলার জন্য মূল সেটিংটি একই:

obj = Obj()
obj.attribute = value  
the_value = obj.attribute
del obj.attribute

আপনার এড়ানো উচিত:

def set_property(property,value):  
def get_property(property):  

প্রথমত, উপরেরটি কাজ করে না, কারণ সম্পত্তিটি (সাধারণত self) সেট করা হবে এই উদাহরণটির জন্য আপনি কোনও যুক্তি সরবরাহ করেন না যা হ'ল:

class Obj:

    def set_property(self, property, value): # don't do this
        ...
    def get_property(self, property):        # don't do this either
        ...

দ্বিতীয়ত, এটি দুটি বিশেষ পদ্ধতির উদ্দেশ্যটিকে নকল করে __setattr__এবং __getattr__

তৃতীয়ত, আমাদের setattrএবং getattrবিল্টিন ফাংশনগুলিও রয়েছে।

setattr(object, 'property_name', value)
getattr(object, 'property_name', default_value)  # default is optional

@propertyপ্রসাধক getters এবং setters তৈরি করার জন্য নয়।

উদাহরণস্বরূপ, মান নির্ধারণের জন্য বিধিনিষেধ স্থাপনের জন্য আমরা সেটিং আচরণটি পরিবর্তন করতে পারি:

class Protective(object):

    @property
    def protected_value(self):
        return self._protected_value

    @protected_value.setter
    def protected_value(self, value):
        if acceptable(value): # e.g. type or range check
            self._protected_value = value

সাধারণভাবে, আমরা propertyসরাসরি এট্রিবিউট ব্যবহার করা এবং এড়াতে চাই ।

পাইথনের ব্যবহারকারীরা এটি প্রত্যাশা করছেন। সর্বনিম্ন-আশ্চর্যের নিয়ম অনুসরণ করে, আপনার বিপরীতে যদি আপনার কাছে খুব চাপ দেওয়ার কারণ না থাকে তবে আপনার ব্যবহারকারীরা তাদের প্রত্যাশাটি কী দেওয়ার চেষ্টা করবেন।

প্রদর্শন

উদাহরণস্বরূপ, বলুন যে আমাদের 0 এবং 100 সমেতের মধ্যে একটি পূর্ণসংখ্যার জন্য আমাদের অবজেক্টের সুরক্ষিত বৈশিষ্ট্যটি প্রয়োজন ছিল এবং এর সঠিক ব্যবহারের বিষয়ে ব্যবহারকারীকে অবহিত করতে উপযুক্ত বার্তাগুলি সহ এর মুছে ফেলা রোধ করে:

class Protective(object):
    """protected property demo"""
    #
    def __init__(self, start_protected_value=0):
        self.protected_value = start_protected_value
    # 
    @property
    def protected_value(self):
        return self._protected_value
    #
    @protected_value.setter
    def protected_value(self, value):
        if value != int(value):
            raise TypeError("protected_value must be an integer")
        if 0 <= value <= 100:
            self._protected_value = int(value)
        else:
            raise ValueError("protected_value must be " +
                             "between 0 and 100 inclusive")
    #
    @protected_value.deleter
    def protected_value(self):
        raise AttributeError("do not delete, protected_value can be set to 0")

(দ্রষ্টব্য যা __init__উল্লেখ করে self.protected_valueতবে সম্পত্তির পদ্ধতিগুলি উল্লেখ করে self._protected_value। এটি এমনটি __init__যাতে এটি "সুরক্ষিত" রয়েছে তা নিশ্চিত করে সর্বজনীন API এর মাধ্যমে সম্পত্তিটি ব্যবহার করে))

এবং ব্যবহার:

>>> p1 = Protective(3)
>>> p1.protected_value
3
>>> p1 = Protective(5.0)
>>> p1.protected_value
5
>>> p2 = Protective(-5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
  File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> p1.protected_value = 7.3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 17, in protected_value
TypeError: protected_value must be an integer
>>> p1.protected_value = 101
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 15, in protected_value
ValueError: protectected_value must be between 0 and 100 inclusive
>>> del p1.protected_value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 18, in protected_value
AttributeError: do not delete, protected_value can be set to 0

নামগুলি কি গুরুত্বপূর্ণ?

হ্যাঁ তারা করে.setterএবং .deleterমূল সম্পত্তির অনুলিপি তৈরি করুন। এটি সাবক্লাসগুলি পিতামাতার মধ্যে আচরণটি পরিবর্তন না করে আচরণকে সঠিকভাবে সংশোধন করার অনুমতি দেয়।

class Obj:
    """property demo"""
    #
    @property
    def get_only(self):
        return self._attribute
    #
    @get_only.setter
    def get_or_set(self, value):
        self._attribute = value
    #
    @get_or_set.deleter
    def get_set_or_delete(self):
        del self._attribute

এখন এটি কাজ করার জন্য, আপনাকে সংশ্লিষ্ট নামগুলি ব্যবহার করতে হবে:

obj = Obj()
# obj.get_only = 'value' # would error
obj.get_or_set = 'value'  
obj.get_set_or_delete = 'new value'
the_value = obj.get_only
del obj.get_set_or_delete
# del obj.get_or_set # would error

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

উপসংহার

সাধারণ বৈশিষ্ট্য দিয়ে শুরু করুন।

আপনার যদি পরে সেটিং, পাওয়ার এবং মুছে ফেলার জন্য কার্যকারিতা প্রয়োজন হয় তবে আপনি এটিকে সম্পত্তি ডেকরেটারের সাথে যুক্ত করতে পারেন।

নামযুক্ত ফাংশনগুলি এড়িয়ে চলুন set_...এবং get_...- যা বৈশিষ্ট্যের জন্য এটি।


উপলভ্য কার্যকারিতা সদৃশ করার পাশাপাশি, কেন আপনার নিজের সেটটার এবং গেটরগুলি এড়ানো উচিত? আমি বুঝতে পারি এটি পাইথোনিক উপায়ে নাও হতে পারে, তবে সত্যিই কি অন্যরকম সমস্যার মুখোমুখি হতে পারে?
ব্যবহারকারী 1350191

4
আপনার ডেমোতে, __init__পদ্ধতিটি উল্লেখ করে self.protected_valueতবে গেটর এবং সেটটারগুলি উল্লেখ করে self._protected_value। আপনি কিভাবে দয়া করে ব্যাখ্যা করতে পারেন? আমি আপনার কোডটি পরীক্ষা করেছি এবং এটি যেমনটি কাজ করে - তাই এটি কোনও টাইপ নয় not
কোডফোরস্টার

2
@ কোডফোরস্টার আমি আগেই আমার জবাবটি প্রত্যাশা করছিলাম তবে আমি যতক্ষণ না পারব ততক্ষণ এই মন্তব্যটি যথেষ্ট হবে। আমি আশা করি আপনি এটি দেখতে পাবেন যে এটি "সুরক্ষিত" আছে তা নিশ্চিত করে এটি জনসাধারণের API এর মাধ্যমে সম্পত্তিটি ব্যবহার করে। কোনও সম্পত্তি দিয়ে এটিকে "সুরক্ষা" দেওয়া এবং তারপরে __init__এটির পরিবর্তে অ-পাবলিক এপিআই ব্যবহার করার কোনও অর্থ হবে না?
অ্যারন হল

2
হ্যাঁ, @ অ্যারোনহল এটি এখনই পেয়েছেন। আমি বুঝতে পারিনি self.protected_value = start_protected_valueআসলে সেটার ফাংশনটি কল করছে; আমি ভেবেছিলাম এটি একটি অ্যাসাইনমেন্ট ছিল।
কোডফোরস্টার

1
imho এটি গ্রহণযোগ্য উত্তর হওয়া উচিত, যদি আমি সঠিকভাবে বুঝতে পারি যে অজগর উদাহরণস্বরূপ জাভার তুলনায় ঠিক বিপরীত পয়েন্টটি নেয়।
অজগরটিতে

27
In [1]: class test(object):
    def __init__(self):
        self.pants = 'pants'
    @property
    def p(self):
        return self.pants
    @p.setter
    def p(self, value):
        self.pants = value * 2
   ....: 
In [2]: t = test()
In [3]: t.p
Out[3]: 'pants'
In [4]: t.p = 10
In [5]: t.p
Out[5]: 20

17

ব্যবহার @propertyএবং @attribute.setterআপনাকে কেবল "পাইথোনিক" উপায়টি ব্যবহার করতে সহায়তা করে না তবে অবজেক্টটি তৈরি করার সময় এবং এটিকে পরিবর্তন করার সময় উভয় বৈশিষ্ট্যের বৈধতা পরীক্ষা করতে সহায়তা করে।

class Person(object):
    def __init__(self, p_name=None):
        self.name = p_name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, new_name):
        if type(new_name) == str: #type checking for name property
            self._name = new_name
        else:
            raise Exception("Invalid value for name")

এটির মাধ্যমে আপনি _nameক্লায়েন্ট বিকাশকারীদের কাছ থেকে বৈশিষ্ট্যটি 'আড়াল করুন' এবং নামের সম্পত্তি ধরণের চেকও সম্পাদন করেন। দ্রষ্টব্য যে দীক্ষার সময়ও এই পদ্ধতির অনুসরণ করে সেটারটি কল হয়। তাই:

p = Person(12)

পরিচালিত হবে:

Exception: Invalid value for name

কিন্তু:

>>>p = person('Mike')
>>>print(p.name)
Mike
>>>p.name = 'George'
>>>print(p.name)
George
>>>p.name = 2.3 # Causes an exception

16

@propertyসাজসজ্জার পরীক্ষা করুন ।


33
এটি প্রায় একটি লিঙ্ক-শুধুমাত্র উত্তর।
অ্যারন হল


7
এটি কীভাবে সম্পূর্ণ উত্তর? একটি লিঙ্ক একটি উত্তর নয়।
অ্যান্ডি_আনাদিডি̷

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

যাই হোক না কেন, এই উত্তরটি অন্য উত্তরের জন্য দরকারী কিছু যুক্ত করে না এবং আদর্শভাবে মুছে ফেলা উচিত।
জর্জি

5

আপনি অ্যাকসেসর / মিউটরগুলি (যেমন @attr.setterএবং @property) ব্যবহার করতে পারেন বা নাও ব্যবহার করতে পারেন তবে সর্বাধিক গুরুত্বপূর্ণ বিষয়টি সামঞ্জস্যপূর্ণ হতে হবে!

আপনি যদি @propertyকোনও বৈশিষ্ট্যটি সহজেই অ্যাক্সেস করতে ব্যবহার করেন তবে, যেমন

class myClass:
    def __init__(a):
        self._a = a

    @property
    def a(self):
        return self._a

প্রতিটি * বৈশিষ্ট্য অ্যাক্সেস করতে এটি ব্যবহার করুন ! কিছু বৈশিষ্ট্য ব্যবহার করে অ্যাক্সেস করা এবং অ্যাক্সেসর ছাড়া @propertyকিছু অন্যান্য সম্পত্তি জনসমক্ষে (যেমন আন্ডারস্কোর ছাড়া নাম) রেখে দেওয়া একটি খারাপ অভ্যাস হবে , উদাহরণস্বরূপ না

class myClass:
    def __init__(a, b):
        self.a = a
        self.b = b

    @property
    def a(self):
        return self.a

দ্রষ্টব্য যে self.bএখানে প্রকাশ্য অ্যাক্সেসর নেই যদিও এটি সর্বজনীন।

সঙ্গে একইভাবে setters (অথবা mutators ), বিনা দ্বিধায় ব্যবহার করুন @attribute.setterকিন্তু সামঞ্জস্যপূর্ণ হতে! যখন আপনি যেমন

class myClass:
    def __init__(a, b):
        self.a = a
        self.b = b 

    @a.setter
    def a(self, value):
        return self.a = value

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

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

সবশেষে, পিইপি 8 এবং গুগল স্টাইল গাইডের পরামর্শ:

পিইপি 8, ডিজাইনিং ফর হেরিরিটেন্স বলেছেন:

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

অন্যদিকে, গুগল স্টাইল গাইড পাইথন ল্যাঙ্গুয়েজ বিধি / বৈশিষ্ট্য অনুসারে সুপারিশটি হ'ল:

অ্যাক্সেস করতে বা সেট করতে যেখানে আপনি সাধারণত সাধারণ, লাইটওয়েট অ্যাকসেসর বা সেটার পদ্ধতি ব্যবহার করেন সেখানে নতুন কোডে বৈশিষ্ট্যগুলি ব্যবহার করুন। @propertyসাজসজ্জার দিয়ে সম্পত্তি তৈরি করা উচিত ।

এই পদ্ধতির সুবিধা:

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

এবং কনস:

objectপাইথন 2 থেকে উত্তরাধিকার সূত্রে আবশ্যক 2 অপারেটর ওভারলোডিংয়ের মতো পার্শ্ব-প্রতিক্রিয়াগুলি লুকিয়ে রাখতে পারে। সাবক্লাস জন্য বিভ্রান্তিকর হতে পারে।


1
আমি দৃ strongly়ভাবে একমত না। আমার অবজেক্টে যদি আমার 15 টি বৈশিষ্ট্য থাকে এবং আমি চাই যে এটির সাথে তুলনা করা হবে তবে বাকীগুলিও @propertyব্যবহার @propertyকরা খারাপ সিদ্ধান্ত বলে মনে হচ্ছে।
কোয়েলক্লেফ

সম্মত হন তবে কেবলমাত্র যদি আপনার প্রয়োজনীয় এই নির্দিষ্ট বৈশিষ্ট্য সম্পর্কে নির্দিষ্ট কিছু থাকে তবে @property(যেমন কোনও বৈশিষ্ট্য ফেরার আগে কিছু বিশেষ যুক্তি সম্পাদন)। অন্যথায় আপনি কেন @properyঅন্যের সাথে একটি বৈশিষ্ট্য সাজাবেন?
টমাসজ বার্টকোয়িয়াক

@ কিউলক্লেফ পোস্টটিতে সিডেনোটটি দেখুন (নক্ষত্রের সাথে চিহ্নিত)
টমাসজ বার্টকোয়িয়াক

আচ্ছা ... আপনি যদি সিডেনোট দ্বারা উল্লিখিত একটি জিনিস না করে থাকেন, তবে আপনার শুরু করা উচিত নয় @property, তাই না? যদি আপনার গিটারটি হয় return this._xএবং আপনার সেটারটি হয় this._x = new_x, তবে এটিকে ব্যবহার @propertyকরা মোটেও মূর্খ।
কোয়েলক্লেফ

1
হুম, সম্ভবত। আমি ব্যক্তিগতভাবে বলব যে এটি ঠিক নয় --- এটি সম্পূর্ণরূপে অতিমাত্রায়। তবে আমি দেখতে পাচ্ছি আপনি কোথা থেকে এসেছেন। আমি অনুমান করি যে আমি আপনার পোস্টটি কেবল এই বলেই পড়েছি যে "ব্যবহারের সময় সর্বাধিক গুরুত্বপূর্ণ বিষয়টি @propertyধারাবাহিক হওয়া"।
Quelklef

-1

আপনি যাদু পদ্ধতি __getattribute__এবং ব্যবহার করতে পারেন __setattr__

class MyClass:
    def __init__(self, attrvalue):
        self.myattr = attrvalue
    def __getattribute__(self, attr):
        if attr == "myattr":
            #Getter for myattr
    def __setattr__(self, attr):
        if attr == "myattr":
            #Setter for myattr

সচেতন থাকুন __getattr__এবং __getattribute__এক নয়। __getattr__কেবল তখনই অনুরোধ করা হয় যখন বৈশিষ্ট্যটি পাওয়া যায় না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.