@ প্রপার্টি সাজসজ্জার কাজ কিভাবে করে?


979

আমি বিল্ট-ইন ফাংশনটি কীভাবে কাজ করে তা বুঝতে চাই property। যা আমাকে বিভ্রান্ত করে তা হ'ল এটি propertyএকটি ডেকরেটর হিসাবেও ব্যবহার করা যেতে পারে, তবে এটি কেবল তখন অন্তর্নির্মিত ফাংশন হিসাবে ব্যবহৃত হয় এবং সজ্জা হিসাবে ব্যবহৃত না হয়েই যুক্তি নেয়।

এই উদাহরণটি ডকুমেন্টেশন থেকে :

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

    def getx(self):
        return self._x
    def setx(self, value):
        self._x = value
    def delx(self):
        del self._x
    x = property(getx, setx, delx, "I'm the 'x' property.")

propertyএর আর্গুমেন্ট getx, setx, delxএবং ডক পংক্তি।

নীচের কোডে propertyসাজসজ্জার হিসাবে ব্যবহৃত হয়। এর অবজেক্টটি হ'ল xফাংশন, তবে উপরের কোডে আর্গুমেন্টগুলিতে কোনও অবজেক্ট ফাংশনের কোনও স্থান নেই।

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

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

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

    @x.deleter
    def x(self):
        del self._x

এবং, কীভাবে x.setterএবং x.deleterসাজসজ্জা তৈরি করা হয়? আমি দ্বিধান্বিত.



3
propertyআসলে এটি একটি শ্রেণি (কোনও ফাংশন নয়), যদিও এটি সম্ভবত __init__()পদ্ধতিটিকে কল করে যখন আপনি কোনও বস্তু তৈরি করেন অবশ্যই। help(property)টার্মিনাল থেকে ব্যবহার অন্তর্দৃষ্টিপূর্ণ। helpকোনও কারণে ক্লাসও হয়।
ব্রুটসর্ফুজথ্রিক্স

আমি মনে করি এই লিঙ্কটি একটি ভাল উদাহরণ সরবরাহ করে: [সম্পত্তি] ( জার্নালদেব / 14893 / python- property- decorator )
শেং দ্বি

4
@ শুলে ২ বছরের পুরানো থ্রেড, কিন্তু এখনও: সবকিছুই একটি শ্রেণি। এমনকি ক্লাস।
আর্টেমিস এখনও

2
এটি আমার কাছেও বিভ্রান্তিকর ছিল। অবশেষে আমি একটি নিবন্ধ পেয়েছি যা এটি আমার জন্য ভেঙে ফেলতে সক্ষম হয়েছিল। আমি আশা করি এটি অন্য কাউকে সহায়তা করে। programiz.com/python-pogramming/property আমি সাইটের সাথে কোনওভাবেই অনুমোদিত নয়।
jjwdesign

উত্তর:


1008

property()ফাংশনটি একটি বিশেষ বর্ণনাকারী বস্তুর :

>>> property()
<property object at 0x10ff07940>

এটি এই পদার্থের অতিরিক্ত পদ্ধতি রয়েছে:

>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>

এগুলি সজ্জকার হিসাবেও কাজ করে । তারা একটি নতুন সম্পত্তি বস্তু ফেরত দেয়:

>>> property().getter(None)
<property object at 0x10ff079f0>

এটি পুরানো অবজেক্টের একটি অনুলিপি, তবে প্রতিস্থাপন করা ফাংশনগুলির একটিতে।

মনে রাখবেন, @decoratorসিনট্যাক্সটি কেবল সিনট্যাকটিক চিনি; বাক্য গঠন:

@property
def foo(self): return self._foo

সত্যিই একই জিনিস মানে

def foo(self): return self._foo
foo = property(foo)

সুতরাং fooফাংশন দ্বারা প্রতিস্থাপিত হয় property(foo), যা আমরা উপরে দেখেছি একটি বিশেষ অবজেক্ট। তারপরে আপনি যখন ব্যবহার করবেন @foo.setter(), আপনি যা করছেন তা কল করুনproperty().setter আমি আপনাকে উপরে দেখিয়েছি, যা সম্পত্তিটির একটি নতুন অনুলিপি দেয়, তবে এবার সেটার ফাংশনটি সজ্জিত পদ্ধতির সাথে প্রতিস্থাপন করা হয়েছে।

নিম্নলিখিত সিকোয়েন্সগুলি সেই ডেকরেটার পদ্ধতিগুলি ব্যবহার করে একটি পূর্ণ-অন সম্পত্তি তৈরি করে।

প্রথমে আমরা কিছু গেমস এবং একটি propertyগেটর দিয়ে একটি অবজেক্ট তৈরি করি :

>>> def getter(self): print('Get!')
... 
>>> def setter(self, value): print('Set to {!r}!'.format(value))
... 
>>> def deleter(self): print('Delete!')
... 
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True

এর পরে আমরা .setter()একটি সেটার যুক্ত করতে পদ্ধতিটি ব্যবহার করি :

>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True

সর্বশেষে আমরা পদ্ধতিটির সাথে একটি মুছে ফেলা যুক্ত করব .deleter():

>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True

কিন্তু শেষ না অন্তত, propertyবস্তু একটি হিসাবে কাজ করে বর্ণনাকারী বস্তুর , তাই এটি হয়ে গেছে .__get__(), .__set__()এবং .__delete__()পদ্ধতি পেয়ে, সেটিং এবং মুছে ফেলার দৃষ্টান্ত অ্যাট্রিবিউট মধ্যে হুক:

>>> class Foo: pass
... 
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!

বর্ণনাকারী হাওটোতে খাঁটি পাইথনেরproperty() ধরণের নমুনা প্রয়োগ রয়েছে :

class Property:
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

10
খুব ভালো. আপনি যে পছন্দটি পরে ফলাফলটি Foo.prop = propকরতে পারেন তা যুক্ত করতে পারেন Foo().prop = 5; pront Foo().prop; del Foo().prop
glglgl

12
পদ্ধতি অবজেক্টগুলি ফ্লাইতে তৈরি করা হয় এবং যদি পাওয়া যায় তবে একই মেমরির অবস্থানটি পুনরায় ব্যবহার করতে পারে
মার্টিজন পিটারস

1
@ মারকাসমেসকেনেন: আমি বরং ব্যবহারকারীর type()বৈশিষ্ট্য এবং পদ্ধতিগুলিকে স্ট্যান্ডার্ড ফাংশন এবং অপারেটর দ্বারা এক্সটেনশন পয়েন্ট হিসাবে ব্যবহার করতে চাইছি হিসাবে ব্যবহার করি।
Martijn Pieters

2
@ মারকাসমেসকেনেন: কারণ বস্তুটি অপরিবর্তনীয় এবং আপনি যদি এটির জায়গায় স্থান পরিবর্তন করেন তবে আপনি এটি একটি সাবক্লাসে বিশেষজ্ঞ করতে পারবেন না।
মার্টিজন পিটারস

5
@ মারকাসমেসকেনেন: পাইথনকে সেটার ছাড়াই ওভাররাইডিং গেটার দেখুন ; যদি @human.name.getterরদবদল propertyইন-জায়গা বস্তুর পরিবর্তে একটি নতুন ফিরে human.nameঅ্যাট্রিবিউট পরিবর্তন করা হবে, যে সুপারক্লাস আচরণ পরিবর্তন।
মার্টিজন পিটারস

200

ডকুমেন্টেশন বলছে এটি কেবলমাত্র পঠনযোগ্য বৈশিষ্ট্য তৈরির জন্য একটি শর্টকাট। সুতরাং

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

সমতুল্য

def getx(self):
    return self._x
x = property(getx)

19
সম্পূর্ণ প্রসঙ্গ (সর্বাধিক উত্সাহিত উত্তর) ভাল তবে এই উত্তরটি অন্য কেউ কেন @propertyতাদের শ্রেণিতে সজ্জা হিসাবে ব্যবহার করেছিল তা নির্ধারণের জন্য কার্যত কার্যকর ছিল ।
আইজোসেফ

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

111

এখানে কীভাবে @propertyপ্রয়োগ করা যেতে পারে তার একটি ন্যূনতম উদাহরণ :

class Thing:
    def __init__(self, my_word):
        self._word = my_word 
    @property
    def word(self):
        return self._word

>>> print( Thing('ok').word )
'ok'

অন্যথায় wordএকটি সম্পত্তি পরিবর্তে একটি পদ্ধতি অবশেষ।

class Thing:
    def __init__(self, my_word):
        self._word = my_word
    def word(self):
        return self._word

>>> print( Thing('ok').word() )
'ok'

1
কিভাবে এই উদাহরণে বর্ণন শব্দ () ফাংশন / প্রয়োজন সম্পত্তি সংজ্ঞায়িত করতে জোর করবে Init ?
জেজে

5
কেউ দয়া করে ব্যাখ্যা করতে পারেন যে কেন আমি এখানে থাকার পরিবর্তে এখানে সম্পত্তি ডেকরেটর তৈরি করব self.word = my_word- যা একইভাবে কাজ করবেprint( Thing('ok').word ) = 'ok'
সিলভারস্ল্যাশ

1
@ সিলভারস্ল্যাশ এটি কেবল একটি সহজ উদাহরণ, বাস্তব ব্যবহারের ক্ষেত্রে আরও জটিল পদ্ধতি জড়িত
অ্যালেক্সজি

আপনি দয়া করে আমাকে ব্যাখ্যা করতে পারেন, প্রিন্টিং কীভাবে Thing('ok').wordরানটাইমের সময় অভ্যন্তরীণভাবে ফাংশনটি কল করে?
ভিক্রোবট

83

প্রথম অংশটি সহজ:

@property
def x(self): ...

হিসাবে একই

def x(self): ...
x = property(x)
  • যা, পরিবর্তে, propertyকেবলমাত্র একজন গেটর দিয়ে তৈরি করার জন্য সরলিকৃত বাক্য গঠন ।

পরবর্তী পদক্ষেপটি হ'ল সেটার এবং একটি মুছক দিয়ে এই সম্পত্তিটি প্রসারিত করা। এবং এটি যথাযথ পদ্ধতিগুলির সাথে ঘটে:

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

একটি নতুন সম্পত্তি প্রদান করে যা পুরানো xপ্লাস প্রদত্ত সেটার থেকে সবকিছু উত্তরাধিকার সূত্রে প্রাপ্ত ।

x.deleter একইভাবে কাজ করে।


49

এই নিম্নলিখিত:

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

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

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

    @x.deleter
    def x(self):
        del self._x

হিসাবে একই:

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

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, _x_set, _x_del, 
                    "I'm the 'x' property.")

হিসাবে একই:

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

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, doc="I'm the 'x' property.")
    x = x.setter(_x_set)
    x = x.deleter(_x_del)

হিসাবে একই:

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

    def _x_get(self):
        return self._x
    x = property(_x_get, doc="I'm the 'x' property.")

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

    def _x_del(self):
        del self._x
    x = x.deleter(_x_del)

যা একই:

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

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

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

    @x.deleter
    def x(self):
        del self._x

4
প্রথম এবং শেষ কোড উদাহরণগুলি একই (ভার্বাটিম)।
অ্যাডোমাস বালিয়ুকা

47

নীচে এখান@property থেকে নেওয়া একটি রিফ্যাক্টর কোড থাকতে হবে তখন কীভাবে সহায়তা করতে পারে তার নীচে অন্য উদাহরণ দেওয়া হল (আমি কেবল এটি নীচে সংক্ষেপে বলি):

কল্পনা করুন আপনি এর Moneyমতো একটি শ্রেণি তৈরি করেছেন:

class Money:
    def __init__(self, dollars, cents):
        self.dollars = dollars
        self.cents = cents

এবং কোনও ব্যবহারকারী এই শ্রেণীর উপর নির্ভর করে একটি লাইব্রেরি তৈরি করেন যেখানে তিনি উদাহরণ ব্যবহার করেন

money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.

এখন ধরা যাক আপনি নিজের Moneyশ্রেণি পরিবর্তন করার সিদ্ধান্ত নিয়েছেন dollarsএবং centsবৈশিষ্ট্যগুলি এবং বৈশিষ্ট্যগুলি থেকে মুক্তি পাবেন তবে পরিবর্তে কেবলমাত্র মোট সেন্টের পরিমাণ ট্র্যাক করার সিদ্ধান্ত নিন:

class Money:
    def __init__(self, dollars, cents):
        self.total_cents = dollars * 100 + cents

যদি উপরে বর্ণিত ব্যবহারকারী এখন আগের মতো তার লাইব্রেরি চালানোর চেষ্টা করে

money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))

এটি একটি ত্রুটি হতে হবে

অ্যাট্রিবিউটআরার: 'অর্থ' অবজেক্টের কোনও 'ডলার' নেই

এর অর্থ হ'ল এখন যে কেউ আপনার মূল Moneyশ্রেণীর উপর নির্ভর করে তাদের কোডের সমস্ত লাইন পরিবর্তন করতে হবে যেখানে dollarsএবং centsব্যবহার করা হয়েছে যা অত্যন্ত বেদনাদায়ক হতে পারে ... সুতরাং, কীভাবে এড়ানো যায়? ব্যবহার করে @property!

ঐটা কিভাবে:

class Money:
    def __init__(self, dollars, cents):
        self.total_cents = dollars * 100 + cents

    # Getter and setter for dollars...
    @property
    def dollars(self):
        return self.total_cents // 100

    @dollars.setter
    def dollars(self, new_dollars):
        self.total_cents = 100 * new_dollars + self.cents

    # And the getter and setter for cents.
    @property
    def cents(self):
        return self.total_cents % 100

    @cents.setter
    def cents(self, new_cents):
        self.total_cents = 100 * self.dollars + new_cents

যখন আমরা এখন আমাদের লাইব্রেরি থেকে কল করি

money = Money(27, 12)

print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.

এটি প্রত্যাশা মতো কাজ করবে এবং আমাদের লাইব্রেরিতে কোডের একক লাইন পরিবর্তন করতে হবে না! আসলে, আমাদের এমনকি এটি জানতে হবে না যে আমরা যে লাইব্রেরিটির উপর নির্ভর করি তা পরিবর্তিত হয়েছে।

এছাড়াও setterকাজ সূক্ষ্ম:

money.dollars += 2
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 12 cents.

money.cents += 10
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 22 cents.

আপনি @propertyবিমূর্ত ক্লাসেও ব্যবহার করতে পারেন ; আমি এখানে একটি ন্যূনতম উদাহরণ দেয় ।


আপনার সংক্ষিপ্তসারটি খুব ভাল, উদাহরণটি ওয়েবসাইটটি খানিকটা অদ্ভুত লাগে .. একটি শিক্ষানবিশ জিজ্ঞাসা করবেন .. কেন আমরা কেবল আটকে থাকতে পারি না self.dollar = dollars? আমরা @ প্রপার্টি দিয়ে অনেক কিছু করেছি, তবে মনে হয় কোনও নিষ্ক্রিয় কার্যকারিতা যুক্ত হয়নি।
শেং দ্বি

1
@ শেংবি: প্রকৃত উদাহরণের দিকে তেমন বেশি মনোনিবেশ করবেন না তবে অন্তর্নিহিত নীতিটির প্রতি আরও বেশি মনোযোগ দেবেন না: যদি - কোন কারণের জন্য - আপনাকে রিফ্যাক্টর কোড দিতে হয়, আপনি অন্যের কোডকে প্রভাবিত না করে এটি করতে পারেন।
ক্লাব

21

আমি এখানে সমস্ত পোস্ট পড়েছি এবং বুঝতে পেরেছিলাম যে আমাদের বাস্তব জীবনের উদাহরণের প্রয়োজন হতে পারে। কেন, আসলে, আমাদের @ প্রপার্টি আছে? সুতরাং, এমন ফ্ল্যাশ অ্যাপ বিবেচনা করুন যেখানে আপনি প্রমাণীকরণ সিস্টেমটি ব্যবহার করেন। আপনি এতে একটি মডেল ব্যবহারকারী ঘোষণা করুন models.py:

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))

    ...

    @property
    def password(self):
        raise AttributeError('password is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

এই কোডটিতে আমরা "লুকানো" বৈশিষ্ট্যটি passwordব্যবহার করেছি @propertyযা AttributeErrorযখন আপনি সরাসরি অ্যাক্সেস করার চেষ্টা করেন তখন আপনি যা দৃ trig ়তার সাথে তদন্ত করে, যখন আমরা @ সম্পত্তি.setter ব্যবহার করি প্রকৃত উদাহরণ পরিবর্তনশীল সেট করতে password_hash

এখন auth/views.pyআমরা এর সাথে কোনও ব্যবহারকারীকে ইনস্ট্যান্ট করতে পারি:

...
@auth.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        user = User(email=form.email.data,
                    username=form.username.data,
                    password=form.password.data)
        db.session.add(user)
        db.session.commit()
...

passwordকোনও ব্যবহারকারী ফর্মটি পূরণ করার সময় নিবন্ধের ফর্ম থেকে আসে এমন নোটের বৈশিষ্ট্যটি লক্ষ্য করুন । পাসওয়ার্ড নিশ্চিতকরণটি প্রথম প্রান্তে ঘটে থাকে EqualTo('password', message='Passwords must match')(যদি আপনি ভাবছেন তবে এটি ফ্লাস্ক ফর্ম সম্পর্কিত একটি আলাদা বিষয়)।

আমি আশা করি এই উদাহরণটি কার্যকর হবে


18

এই পয়েন্টটি সেখানে অনেক লোক সাফ করে দিয়েছে তবে এখানে একটি সরাসরি পয়েন্ট যা আমি অনুসন্ধান করছিলাম। @ প্রপার্টি ডেকরেটারের সাথে এটি শুরু করা গুরুত্বপূর্ণ বলে আমি মনে করি। উদাহরণ: -

class UtilityMixin():
    @property
    def get_config(self):
        return "This is property"

"Get_config ()" ফাংশনটির কলিং এইভাবে কাজ করবে।

util = UtilityMixin()
print(util.get_config)

আপনি যদি লক্ষ্য করেন যে আমি ফাংশনটি কল করার জন্য "()" বন্ধনী ব্যবহার করি নি। এটিই মূল জিনিসটি যা আমি @ প্রপার্টি ডেকরেটারের জন্য অনুসন্ধান করেছিলাম। যাতে আপনি আপনার ফাংশনটি ভেরিয়েবলের মতো ব্যবহার করতে পারেন।


1
এই বিমূর্ত ধারণাটি ঘনীভূত করতে খুব দরকারী পয়েন্ট।
ইনফো

18

পাইথন সাজসজ্জা দিয়ে শুরু করা যাক।

পাইথন ডেকরেটার এমন একটি ফাংশন যা ইতিমধ্যে সংজ্ঞায়িত ফাংশনে কিছু অতিরিক্ত কার্যকারিতা যুক্ত করতে সহায়তা করে।

পাইথনে, সমস্ত কিছুই একটি বস্তু। পাইথনে ফাংশন হ'ল প্রথম-শ্রেণীর অবজেক্টস যার অর্থ তারা ভেরিয়েবলের মাধ্যমে রেফারেন্স করতে পারে, তালিকাগুলিতে যোগ করা যায়, অন্য ফাংশনে আর্গুমেন্ট হিসাবে পাস করা হয় ইত্যাদি that

নিম্নলিখিত কোড স্নিপেট বিবেচনা করুন।

def decorator_func(fun):
    def wrapper_func():
        print("Wrapper function started")
        fun()
        print("Given function decorated")
        # Wrapper function add something to the passed function and decorator 
        # returns the wrapper function
    return wrapper_func

def say_bye():
    print("bye!!")

say_bye = decorator_func(say_bye)
say_bye()

# Output:
#  Wrapper function started
#  bye
#  Given function decorated

এখানে, আমরা বলতে পারি যে ডেকোরেটর ফাংশনটি আমাদের বলে_হেলো ফাংশনটি সংশোধন করেছে এবং এতে কোডের অতিরিক্ত কিছু লাইন যুক্ত করেছে।

সাজসজ্জার জন্য পাইথন সিনট্যাক্স

def decorator_func(fun):
    def wrapper_func():
        print("Wrapper function started")
        fun()
        print("Given function decorated")
        # Wrapper function add something to the passed function and decorator 
        # returns the wrapper function
    return wrapper_func

@decorator_func
def say_bye():
    print("bye!!")

say_bye()

আসুন একটি কেস দৃশ্যের চেয়ে সবকিছু শেষ করা যাক, তবে এর আগে কিছু উফ প্রিন্সিপাল সম্পর্কে কথা বলা যাক।

ডেটা এনক্যাপসুলেশনের মূলনীতিটি নিশ্চিত করার জন্য অনেকগুলি অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং ল্যাঙ্গুয়েজে গেটার এবং সেটটার ব্যবহার করা হয় (এই ডেটাগুলিতে পরিচালিত পদ্ধতিগুলির সাথে ডেটা বান্ডিলিং হিসাবে দেখা হয়))

এই পদ্ধতিগুলি অবশ্যই ডেটা পুনরুদ্ধারের জন্য প্রাপ্তি এবং ডেটা পরিবর্তনের জন্য সেটার।

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

হ্যাঁ, @ প্রপার্টি মূলত গেটরস এবং সিটারগুলি ব্যবহার করার এক অজগর উপায়।

পাইথনের সম্পত্তি হিসাবে একটি দুর্দান্ত ধারণা রয়েছে যা কোনও অবজেক্ট ভিত্তিক প্রোগ্রামারটির জীবনকে আরও সহজ করে তোলে।

আমাদের ধরে নেওয়া যাক আপনি এমন একটি ক্লাস তৈরি করার সিদ্ধান্ত নিয়েছেন যা তাপমাত্রা ডিগ্রি সেলসিয়াসে সঞ্চয় করতে পারে।

class Celsius:
def __init__(self, temperature = 0):
    self.set_temperature(temperature)

def to_fahrenheit(self):
    return (self.get_temperature() * 1.8) + 32

def get_temperature(self):
    return self._temperature

def set_temperature(self, value):
    if value < -273:
        raise ValueError("Temperature below -273 is not possible")
    self._temperature = value

রিফ্যাক্টর কোড, এখানে আমরা কীভাবে সম্পত্তি সহ এটি অর্জন করতে পারতাম।

পাইথনে, সম্পত্তি () হ'ল একটি অন্তর্নির্মিত ফাংশন যা কোনও সম্পত্তি বস্তু তৈরি করে এবং প্রদান করে।

একটি সম্পত্তি বস্তুর তিনটি পদ্ধতি রয়েছে, গেটর (), সেটার () এবং মুছুন ()।

class Celsius:
def __init__(self, temperature = 0):
    self.temperature = temperature

def to_fahrenheit(self):
    return (self.temperature * 1.8) + 32

def get_temperature(self):
    print("Getting value")
    return self.temperature

def set_temperature(self, value):
    if value < -273:
        raise ValueError("Temperature below -273 is not possible")
    print("Setting value")
    self.temperature = value

temperature = property(get_temperature,set_temperature)

এখানে,

temperature = property(get_temperature,set_temperature)

হিসাবে ভেঙে যেতে পারে,

# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)

লক্ষ করার বিষয়:

  • get_tempe साहित्य একটি পদ্ধতির পরিবর্তে সম্পত্তি হিসাবে রয়ে গেছে।

এখন আপনি লিখে তাপমাত্রার মান অ্যাক্সেস করতে পারেন।

C = Celsius()
C.temperature
# instead of writing C.get_temperature()

আমরা আরও এগিয়ে যেতে পারি এবং নামগুলি get_temperature এবং set_temperature সংজ্ঞায়িত করতে পারি না কারণ এগুলি অপ্রয়োজনীয় এবং শ্রেণীর নেমস্পেসকে দূষিত করে।

Pythonic পথ উপরে সমস্যা মোকাবেলা করতে ব্যবহার করা @property

class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    @property
    def temperature(self):
        print("Getting value")
        return self.temperature

    @temperature.setter
    def temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self.temperature = value

লক্ষ করার পয়েন্টগুলি -

  1. একটি মান যা মান পাওয়ার জন্য ব্যবহৃত হয় তা "@ প্রপার্টি" দিয়ে সজ্জিত।
  2. সেটার হিসাবে যে পদ্ধতিটি কাজ করতে হবে তাকে "@ তাপমাত্রা.সেটর" দিয়ে সজ্জিত করা হয়েছে, যদি ফাংশনটি "এক্স" বলা হত, তবে আমরা এটি "@ x.setter" দিয়ে সাজাইয়া দিতে পারি।
  3. আমরা একই নাম এবং "ডিএফ তাপমাত্রা (স্ব)" এবং "ডিএফ তাপমাত্রা (স্ব, এক্স)" দিয়ে বিভিন্ন সংখ্যক পরামিতি সহ "দুটি" পদ্ধতি লিখেছি।

আপনি দেখতে পাচ্ছেন যে কোডটি অবশ্যই কম মার্জিত।

এখন, আসুন একটি বাস্তব জীবনের ব্যবহারিক দৃশ্যের কথা বলি।

ধরা যাক আপনি নিম্নলিখিত হিসাবে একটি ক্লাস ডিজাইন করেছেন:

class OurClass:

    def __init__(self, a):
        self.x = a


y = OurClass(10)
print(y.x)

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

এবং এক দুর্ভাগ্যজনক দিনে, একজন বিশ্বস্ত ক্লায়েন্ট আমাদের কাছে এসে পরামর্শ দিলেন যে "x" এর মান 0 এবং 1000 এর মধ্যে হওয়া উচিত, এটি সত্যিই এক ভয়াবহ দৃশ্য!

বৈশিষ্ট্যগুলির কারণে এটি সহজ: আমরা "x" এর একটি সম্পত্তি সংস্করণ তৈরি করি।

class OurClass:

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

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

    @x.setter
    def x(self, x):
        if x < 0:
            self.__x = 0
        elif x > 1000:
            self.__x = 1000
        else:
            self.__x = x

এটি দুর্দান্ত, তাই না: আপনি কল্পনাযোগ্যতম সহজ বাস্তবায়ন দিয়ে শুরু করতে পারেন এবং ইন্টারফেসটি পরিবর্তন না করেই আপনি কোনও সম্পত্তি সংস্করণে মাইগ্রেট করতে পারেন! সুতরাং সম্পত্তিগুলি কেবল গেটার এবং সেটারের প্রতিস্থাপন নয়!

আপনি এখানে এই বাস্তবায়ন পরীক্ষা করতে পারেন


2
আপনার সেলসিয়াস বর্গটি সেট করার সময় অসীম পুনরাবৃত্তি হতে চলেছে (যার অর্থ ইনস্ট্যান্টেশন উপর)।
টেড পেট্রো

1
@ টেড পেট্রো আমি আপনাকে পাইনি? সেট করার সময় এটি কীভাবে অসীম পুনরাবৃত্তি হবে?
দিব্যংশু রাওয়াত

এটি আসলে পরিষ্কার নয় ... লোকেরা জিজ্ঞাসা করছে কেন, তবে উদাহরণটি বিশ্বাসযোগ্য নয় ...
শেং বাই

1
এটি কেবল একটি মন্তব্য, আমার ব্যক্তিগত মতামত। আপনার উত্তর সত্যিই ভাল হতে পারে। সুতরাং এটি ছেড়ে দিন।
শেং দ্বি

1
শীর্ষে ভোট দেওয়া উত্তরের তুলনায়, এটি একটি মানুষের জন্য ডিজাইন করা হয়েছে; ধন্যবাদ।
ইনফো

6

property@propertyসাজসজ্জার পিছনে একটি বর্গ ।

আপনি সর্বদা এটি পরীক্ষা করতে পারেন:

print(property) #<class 'property'>

আমি সিনট্যাক্সটি help(property)দেখানোর জন্য উদাহরণটি পুনরায় লিখেছিলাম@property

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

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

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

    @x.deleter
    def x(self):
        del self._x

c = C()
c.x="a"
print(c.x)

property()সিনট্যাক্সের সাথে কার্যত অভিন্ন :

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

    def g(self):
        return self._x

    def s(self, v):
        self._x = v

    def d(self):
        del self._x

    prop = property(g,s,d)

c = C()
c.x="a"
print(c.x)

আপনি যেমন দেখতে পাচ্ছেন আমরা কীভাবে সম্পত্তিটি ব্যবহার করি তাতে কোনও পার্থক্য নেই।

প্রশ্নের জবাব দেওয়ার জন্য ক্লাসের @propertyমাধ্যমে ডেকরেটার প্রয়োগ করা হয় property


সুতরাং, প্রশ্নটি propertyক্লাসটি কিছুটা ব্যাখ্যা করার জন্য । এই লাইন:

prop = property(g,s,d)

দীক্ষা ছিল। আমরা এটিকে আবার লিখতে পারি:

prop = property(fget=g,fset=s,fdel=d)

এর অর্থ fget, fsetএবং fdel:

 |    fget
 |      function to be used for getting an attribute value
 |    fset
 |      function to be used for setting an attribute value
 |    fdel
 |      function to be used for del'ing an attribute
 |    doc
 |      docstring

পরবর্তী চিত্রটি ক্লাস থেকে আমাদের থাকা ট্রিপলটি দেখায় property:

এখানে চিত্র বর্ণনা লিখুন

__get__, __set__, এবং __delete__সেখানে হতে হয় উপেক্ষিত । এটি পাইথনে বর্ণনাকারী প্যাটার্নটির বাস্তবায়ন।

সাধারণভাবে, একটি বর্ণনাকারী হ'ল "বাঁধাই আচরণ" সহ একটি অবজেক্ট অ্যাট্রিবিউট, যার বৈশিষ্ট্য অ্যাক্সেসকে ডেস্ক্রিপ্টর প্রোটোকলে পদ্ধতি দ্বারা ওভাররাইড করা হয়।

আমরা সম্পত্তি ব্যবহার করতে পারেন setter, getterএবং deleterপদ্ধতি সম্পত্তিতে ফাংশন জুড়তে অনুমতি। পরবর্তী উদাহরণ পরীক্ষা করুন। s2শ্রেণীর পদ্ধতিতে Cসম্পত্তি দ্বিগুণ হয়ে যাবে

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

    def g(self):
        return self._x

    def s(self, x):
        self._x = x

    def d(self):
        del self._x

    def s2(self,x):
        self._x=x+x


    x=property(g)
    x=x.setter(s)
    x=x.deleter(d)      


c = C()
c.x="a"
print(c.x) # outputs "a"

C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x) # outputs "aa"

1

কোনও সম্পত্তি দুটি উপায়ে ঘোষণা করা যায়।

  • গিটার তৈরি করা, কোনও বৈশিষ্ট্যের জন্য সেটার পদ্ধতি এবং তারপরে সম্পত্তি হিসাবে যুক্তি হিসাবে এটি পাস করা ফাংশনের
  • @ প্রপার্টি ডেকরেটার ব্যবহার করে ।

পাইথনের বৈশিষ্ট্য সম্পর্কে আমি কয়েকটি উদাহরণ লিখেছি ।


আপনি কি আপনার উত্তরটি আপডেট করে বলতে পারেন যে সম্পত্তি একটি শ্রেণি তাই আমি উত্সাহ দিতে পারি।
প্রোস্টি 26'19

1

এখানে সর্বোত্তম ব্যাখ্যার সন্ধান পাওয়া যাবে: পাইথন @ প্রপার্টি ব্যাখ্যা - কীভাবে এবং কখন ব্যবহার করবেন? (সম্পূর্ণ উদাহরণ) সেলভা প্রভাকরণ | নভেম্বর 5, 2018 এ পোস্ট করা হয়েছে

এটি আমাকে কেন কেবল নয় তা বুঝতে সহায়তা করেছে।

https://www.machinelearningplus.com/python/python-property/


0

এখানে আরও একটি উদাহরণ:

##
## Python Properties Example
##
class GetterSetterExample( object ):
    ## Set the default value for x ( we reference it using self.x, set a value using self.x = value )
    __x = None


##
## On Class Initialization - do something... if we want..
##
def __init__( self ):
    ## Set a value to __x through the getter / setter... Since __x is defined above, this doesn't need to be set...
    self.x = 1234

    return None


##
## Define x as a property, ie a getter - All getters should have a default value arg, so I added it - it will not be passed in when setting a value, so you need to set the default here so it will be used..
##
@property
def x( self, _default = None ):
    ## I added an optional default value argument as all getters should have this - set it to the default value you want to return...
    _value = ( self.__x, _default )[ self.__x == None ]

    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Get x = ' + str( _value ) )

    ## Return the value - we are a getter afterall...
    return _value


##
## Define the setter function for x...
##
@x.setter
def x( self, _value = None ):
    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Set x = ' + str( _value ) )

    ## This is to show the setter function works.... If the value is above 0, set it to a negative value... otherwise keep it as is ( 0 is the only non-negative number, it can't be negative or positive anyway )
    if ( _value > 0 ):
        self.__x = -_value
    else:
        self.__x = _value


##
## Define the deleter function for x...
##
@x.deleter
def x( self ):
    ## Unload the assignment / data for x
    if ( self.__x != None ):
        del self.__x


##
## To String / Output Function for the class - this will show the property value for each property we add...
##
def __str__( self ):
    ## Output the x property data...
    print( '[ x ] ' + str( self.x ) )


    ## Return a new line - technically we should return a string so it can be printed where we want it, instead of printed early if _data = str( C( ) ) is used....
    return '\n'

##
##
##
_test = GetterSetterExample( )
print( _test )

## For some reason the deleter isn't being called...
del _test.x

মূলত, এর পরিবর্তে সি (অবজেক্ট) উদাহরণের মতোই আমি পরিবর্তে এক্স ব্যবহার করছি ... আমি __init এও আরম্ভ করব না __init- তেও - ... ভাল .. আমি করি তবে এটি মুছে ফেলা যায় কারণ __x অংশ হিসাবে সংজ্ঞায়িত করা হয়েছে ক্লাসের ....

আউটপুটটি হ'ল:

[ Test Class ] Set x = 1234
[ Test Class ] Get x = -1234
[ x ] -1234

আর যদি আমি self.x = 1234 মন্তব্য Init তারপর আউটপুট হল:

[ Test Class ] Get x = None
[ x ] None

এবং যদি আমি গেটর ফাংশনে _default = কোনটিকে _default = 0 তে সেট না করে রাখি (যেহেতু সমস্ত গেটারের একটি ডিফল্ট মান হওয়া উচিত তবে আমি যা দেখেছি তার থেকে সম্পত্তি মানগুলি পাস করে না তাই আপনি এটি এখানে সংজ্ঞা দিতে পারেন, এবং এটি আসলে খারাপ নয় কারণ আপনি একবারে ডিফল্টটি সংজ্ঞায়িত করতে এবং এটি সর্বত্র ব্যবহার করতে পারেন): ডিফ এক্স (স্ব, _ ডিফল্ট = 0):

[ Test Class ] Get x = 0
[ x ] 0

দ্রষ্টব্য: প্রাপ্তি যুক্তিটি কেবলমাত্র এটির দ্বারা ম্যানিপুলেটেড হয় তা নিশ্চিত করার জন্য এটির দ্বারা মানটি চালিত করার জন্য রয়েছে - মুদ্রণ বিবৃতিগুলির জন্য একই ...

দ্রষ্টব্য: আমি লুয়াতে অভ্যস্ত এবং আমি যখন একটি একক ফাংশন কল করি তখন আমি 10+ হেল্পারকে গতিশীলরূপে তৈরি করতে সক্ষম হয়েছি এবং আমি কোনও বৈশিষ্ট্য ব্যবহার না করে পাইথনের জন্য অনুরূপ কিছু তৈরি করেছিলাম এবং এটি একটি ডিগ্রীতে কাজ করে, তবে, যদিও আগে ফাংশনগুলি তৈরি করা হচ্ছে ব্যবহৃত হচ্ছে, তাদের তৈরি হওয়ার পূর্বে তাদের সাথে ডাকা হওয়ার আগেও কিছু সমস্যা রয়েছে যা অদ্ভুত কারণ এটি সেভাবে কোড করা হয়নি ... আমি লুয়া মেটা-টেবিলগুলির নমনীয়তা এবং আমি প্রকৃত সেটার / গেটার ব্যবহার করতে পারি তার পক্ষে পছন্দ করি মূলত সরাসরি কোনও ভেরিয়েবল অ্যাক্সেস করার পরিবর্তে ... পাইথন দিয়ে কতগুলি কিছু দ্রুত নির্মিত হতে পারে তা আমি পছন্দ করি - উদাহরণস্বরূপ গুই প্রোগ্রামগুলি programs যদিও আমি ডিজাইন করছি সেগুলি অনেকগুলি অতিরিক্ত গ্রন্থাগার ছাড়া সম্ভব নাও হতে পারে - যদি আমি এটি অটোহোটিতে কোড করি তবে আমি সরাসরি আমার প্রয়োজনীয় ডেল কলগুলি অ্যাক্সেস করতে পারি এবং জাভা, সি #, সি ++,

দ্রষ্টব্য: এই ফোরামে কোড আউটপুটটি ভেঙে গেছে - এটির কাজ করার জন্য আমাকে কোডের প্রথম অংশে ফাঁকা স্থান যুক্ত করতে হয়েছিল - অনুলিপি / পেস্ট করার পরে আপনি সমস্ত স্পেসগুলি ট্যাবগুলিতে রূপান্তর করে তা নিশ্চিত করেন .... আমি পাইথনের জন্য ট্যাব ব্যবহার করি কারণ এতে ১০০ লাইনের ফাইলের ফাইলটি স্পেস সহ 512KB থেকে 1MB এবং ট্যাবগুলির সাথে 100 থেকে 200 কেবি হতে পারে যা ফাইলের আকারের জন্য বিশাল পার্থক্যের সমান এবং প্রক্রিয়াকরণের সময় হ্রাস ...

ট্যাবগুলি ব্যবহারকারীর জন্যও সামঞ্জস্য করা যায় - সুতরাং আপনি যদি 2 স্পেস প্রস্থ, 4, 8 বা আপনি যা কিছু করতে চান তা পছন্দ করেন তবে এটি চোখের দৃষ্টির ঘাটতিযুক্ত বিকাশকারীদের জন্য চিন্তাশীল।

দ্রষ্টব্য: ক্লাসে সংজ্ঞায়িত সমস্ত ক্রিয়াকলাপ ফোরাম সফ্টওয়্যারটিতে একটি বাগের কারণে সঠিকভাবে ইন্ডেন্ট করা হয় না - আপনি অনুলিপি / পেস্ট করে নিলে তা নিশ্চিত করুন


-3

একটি মন্তব্য: আমার কাছে পাইথন ২.x এর জন্য, @propertyযখন আমি উত্তরাধিকার সূত্রে পাইনি তখন বিজ্ঞাপন হিসাবে কাজ করিনি object:

class A():
    pass

কিন্তু যখন কাজ করেছেন:

class A(object):
    pass

পাইথন 3 এর জন্য, সর্বদা কাজ করে।


5
এর কারণ পাইথন 2-তে, যে শ্রেণিটি উত্তরাধিকারসূত্রে আসে নি সেগুলি objectএকটি পুরানো-শৈলীর শ্রেণি, এবং পুরাতন-শৈলীর ক্লাসগুলি বর্ণনাকারী প্রোটোকলকে সমর্থন করে না (যা propertyসেভাবে কাজ করার জন্য প্রয়োগ করে)। পাইথন 3 এ, পুরাতন স্টাইলের ক্লাসগুলির আর অস্তিত্ব নেই; সব শ্রেণীর কি আমরা 2. পাইথন নতুন স্টাইলের শ্রেণীর বলা হয়
chepner
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.