আমি এটি এর মতো করছি:
def set_property(property,value):
def get_property(property):
অথবা
object.property = value
value = object.property
আমি পাইথনে নতুন, তাই আমি এখনও বাক্যবিন্যাসটি অন্বেষণ করছি এবং আমি এটি করার জন্য কিছু পরামর্শ চাই।
আমি এটি এর মতো করছি:
def set_property(property,value):
def get_property(property):
অথবা
object.property = value
value = object.property
আমি পাইথনে নতুন, তাই আমি এখনও বাক্যবিন্যাসটি অন্বেষণ করছি এবং আমি এটি করার জন্য কিছু পরামর্শ চাই।
উত্তর:
এটি চেষ্টা করুন: পাইথন সম্পত্তি
নমুনা কোডটি হ'ল:
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
._x
(যা কোনও সম্পত্তি নয়, কেবল একটি সরল বৈশিষ্ট্য) property
মোড়কে বাইপাস করে । কেবলমাত্র রেফারেন্সগুলিতে .x
যেতে হবে property
।
গেটর এবং সেটটারগুলি ব্যবহার করার অজগর উপায় কী?
"পাইথোনিক" উপায়টি "গেটার্স" এবং "সেটটার" ব্যবহার করা নয় , বরং প্রশ্নটি যেমন প্রকাশ করে এবং 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_...
- যা বৈশিষ্ট্যের জন্য এটি।
__init__
পদ্ধতিটি উল্লেখ করে self.protected_value
তবে গেটর এবং সেটটারগুলি উল্লেখ করে self._protected_value
। আপনি কিভাবে দয়া করে ব্যাখ্যা করতে পারেন? আমি আপনার কোডটি পরীক্ষা করেছি এবং এটি যেমনটি কাজ করে - তাই এটি কোনও টাইপ নয় not
__init__
এটির পরিবর্তে অ-পাবলিক এপিআই ব্যবহার করার কোনও অর্থ হবে না?
self.protected_value = start_protected_value
আসলে সেটার ফাংশনটি কল করছে; আমি ভেবেছিলাম এটি একটি অ্যাসাইনমেন্ট ছিল।
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
ব্যবহার @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
@property
সাজসজ্জার পরীক্ষা করুন ।
আপনি অ্যাকসেসর / মিউটরগুলি (যেমন @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 অপারেটর ওভারলোডিংয়ের মতো পার্শ্ব-প্রতিক্রিয়াগুলি লুকিয়ে রাখতে পারে। সাবক্লাস জন্য বিভ্রান্তিকর হতে পারে।
@property
ব্যবহার @property
করা খারাপ সিদ্ধান্ত বলে মনে হচ্ছে।
@property
(যেমন কোনও বৈশিষ্ট্য ফেরার আগে কিছু বিশেষ যুক্তি সম্পাদন)। অন্যথায় আপনি কেন @propery
অন্যের সাথে একটি বৈশিষ্ট্য সাজাবেন?
@property
, তাই না? যদি আপনার গিটারটি হয় return this._x
এবং আপনার সেটারটি হয় this._x = new_x
, তবে এটিকে ব্যবহার @property
করা মোটেও মূর্খ।
@property
ধারাবাহিক হওয়া"।
আপনি যাদু পদ্ধতি __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__
কেবল তখনই অনুরোধ করা হয় যখন বৈশিষ্ট্যটি পাওয়া যায় না।