@ প্রপার্টি বনাম গেটার্স এবং সেটটার ব্যবহার করে


727

এখানে একটি খাঁটি পাইথন-নির্দিষ্ট নকশা প্রশ্ন রয়েছে:

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):
        ...

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

উত্তর:


613

বৈশিষ্ট্য পছন্দ । তারা সেখানে যা আছে তার জন্য এটি।

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

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


90
ডাবল আন্ডারস্কোর সহ অ্যাট্রিবিউট নামগুলি পাইথন দ্বারা বিশেষভাবে পরিচালনা করা হয়; এটি কেবল নিছক সম্মেলন নয়। ডকস.পাইথন.আর.পি.পি.কিউ
6502

63
এগুলি অন্যভাবে পরিচালনা করা হয়, তবে এটি আপনাকে অ্যাক্সেস করা থেকে বিরত রাখে না। পিএস: এডি 30
সি 0

4
এবং কারণ "@" অক্ষরগুলি পাইথন কোডে কুৎসিত, এবং অবসরপ্রাপ্ত @ সেক্রেটারিরা স্প্যাগেটি কোডের মতো একই অনুভূতি দেয়।
বেরি সাকালা

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

69
যদিও আমি বেশিরভাগ ক্ষেত্রেই একমত, @ প্রোপার্টি ডেকরেটারের পিছনে ধীর পদ্ধতিগুলি আড়াল করার বিষয়ে সতর্ক থাকুন। আপনার এপিআই এর ব্যবহারকারী আশা করে যে সম্পত্তি অ্যাক্সেস পরিবর্তনশীল অ্যাক্সেসের মতো কার্য সম্পাদন করে এবং সেই প্রত্যাশা থেকে খুব দূরে বিপথগামী আপনার এপিআই ব্যবহার করতে অপ্রীতিকর করে তুলতে পারে।
Defrex

153

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

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

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


46
@ 50৫০২, যখন আপনি বলেছিলেন “[…] সর্বত্র অর্থহীন ক্লাস যেখানে উদাহরণস্বরূপ একটি সরল tuple করবে”: একটি শ্রেণির উপরের শ্রেণীর সুবিধা হল কোনও শ্রেণীর উদাহরণটি তার অংশগুলি অ্যাক্সেস করার জন্য সুস্পষ্ট নাম সরবরাহ করে, যখন একটি টুপল না । নামগুলি পাঠযোগ্যতা এবং ত্রুটিগুলি এড়ানো এড়াতে টিপলস সাবস্ক্রিপশনের চেয়ে ভাল, বিশেষত যখন বর্তমান মডিউলটির বাইরে পাস করতে হয়।
Hibou57

15
@ হিবিউ ৫7: আমি বলছি না শ্রেণি অকেজো। তবে কখনও কখনও একটি tuple যথেষ্ট বেশি হয়। তবে সমস্যাগুলি হ'ল যাকে বলে যে জাভা বা সি ++ এর সমস্ত কিছুর জন্য ক্লাস তৈরি করা ছাড়া আর কোনও উপায় নেই কারণ অন্যান্য সম্ভাবনাগুলি এই ল্যাঙ্গোগ্যাসগুলিতে ব্যবহার করার জন্য কেবল বিরক্তিকর। পাইথন ব্যবহার করে জাভা / সি ++ প্রোগ্রামিংয়ের আর একটি সাধারণ লক্ষণ অযৌক্তিক ক্লাস এবং জটিল শ্রেণীর শ্রেণিবিন্যাস তৈরি করছে যেখানে পাইথনে আপনি হাঁসের টাইপিংয়ের জন্য কেবল স্বাধীন ক্লাস ব্যবহার করতে পারবেন।
6502

39
@ হিবিউ ৫7 এর জন্য আপনি নামধারীও ব্যবহার করতে পারেন: ডুঘেলম্যান
পাইমোটডব্লিউ

5
@JonathonReinhart: এটা IS 2.6 থেকে মান লাইব্রেরিতে ... দেখুন docs.python.org/2/library/collections.html
6502

1
"যদি প্রয়োজন হয় অবশেষে কোনও সম্পত্তিতে স্থানান্তরিত" তখন এটি সম্ভবত আপনার ক্লাসগুলি ব্যবহার করে কোড ভঙ্গ করে। বৈশিষ্ট্যগুলি প্রায়শই বিধিনিষেধগুলি প্রবর্তন করে - কোনও কোড যা এই বিধিনিষেধগুলির প্রত্যাশা করে না আপনি তা প্রবর্তন করার সাথে সাথেই তা ভেঙে যাবে।
ইয়াককব

118

বৈশিষ্ট্যগুলি ব্যবহারের ফলে আপনি সাধারণ অ্যাট্রিবিউট অ্যাক্সেসগুলি শুরু করতে এবং তারপরে প্রয়োজনীয় এবং পরে সেটারগুলির সাথে তাদের ব্যাক আপ করতে পারেন


3
@ গ্রেগক্রসাক এটিকে অদ্ভুত বলে মনে হচ্ছে কারণ এটি। সম্পত্তি যুক্ত হওয়ার আগে থেকেই "সম্মতি প্রাপ্ত বয়স্কদের জিনিস" একটি অজগর মেম ছিল। এটি অ্যাক্সেস মডিফায়ারগুলির অভাব সম্পর্কে অভিযোগকারী লোকদের স্টক প্রতিক্রিয়া। বৈশিষ্ট্যগুলি যুক্ত করা হলে হঠাৎ করে এনক্যাপসুলেশন আকাঙ্ক্ষিত হয়ে যায়। বিমূর্ত বেস ক্লাসগুলির ক্ষেত্রেও একই ঘটনা ঘটেছিল। "পাইথন সর্বদা যুদ্ধ-বিরক্তি নিয়ে যুদ্ধে লিপ্ত ছিল। স্বাধীনতা দাসত্ব।
জনচিপ

71

সংক্ষিপ্ত উত্তরটি হ'ল: সম্পত্তিগুলি হাতছাড়া করে । সর্বদা.

কখনও কখনও গেটার এবং সেটটারগুলির প্রয়োজন হয়, তবে তারপরেও আমি তাদের বাইরের বিশ্বে "লুকিয়ে" রাখতাম। পাইথন এই কাজটি করার উপায় (প্রচুর আছে 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)

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


1
@ বেসিক ওল্ফ - আমি ভেবেছিলাম এটা স্পষ্টতই পরিষ্কার ছিল যে আমি বেড়ার সম্পত্তির পাশে আছি! :) তবে আমি তা পরিষ্কার করতে আমার উত্তরে একটি প্যারা যুক্ত করছি।
ম্যাক

9
ইঙ্গিত: "সর্বদা" শব্দটি একটি ইঙ্গিত যা লেখক আপনাকে যুক্তি দিয়ে নয়, একটি দৃ .়তার সাথে বোঝানোর চেষ্টা করছেন। বোল্ডফেস ফন্টের উপস্থিতিও তাই। (এর অর্থ, আপনি যদি এর পরিবর্তে সিএপিএস দেখেন তবে - হুয়া - এটি অবশ্যই সঠিক হবে Look দেখুন, "সম্পত্তি" বৈশিষ্ট্যটি জাভা থেকে পৃথক বলে মনে হচ্ছে (পাইথনের ডি ফ্যাক্টো নেমেসিস কোনও কারণে)) এবং তাই পাইথনের সম্প্রদায় গ্রুপপথ এটি আরও ভাল বলে ঘোষণা করে। বাস্তবে, সম্পত্তিগুলি "সুস্পষ্ট বর্ণিত চেয়ে ভাল" নিয়ম লঙ্ঘন করে, তবে কেউ এটি স্বীকার করতে চায় না। এটি এটিকে ভাষায় পরিণত করেছে, সুতরাং এখন এটি টোটোলজিকাল যুক্তির মাধ্যমে "পাইথোনিক" হিসাবে ঘোষণা করা হয়েছে।
স্টুয়ার্ট বার্গ

3
কোন অনুভূতিতে আঘাত না। :-P আমি কেবল এটি নির্দেশ করার চেষ্টা করছি যে "পাইথোনিক" সম্মেলনগুলি এই ক্ষেত্রে অসঙ্গত: "স্পষ্টকৃতের চেয়ে স্পষ্টত ভাল" এটি ব্যবহারের সাথে সরাসরি দ্বন্দ্ব property। (এটি একটি সাধারণ অ্যাসাইনমেন্টের মতো দেখায় , তবে এটি একটি ফাংশনকে ডাকে)) সুতরাং, "পাইথোনিক" মূলত অর্থহীন শব্দ, টোটোলজিকাল সংজ্ঞা ব্যতীত: "পাইথোনিক সম্মেলন এমন জিনিস যা আমরা পাইথোনিক হিসাবে সংজ্ঞায়িত করেছি" "
স্টুয়ার্ট বার্গ

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

1
আমি রাজি নই। আমি বেশিরভাগ পরিস্থিতিতে বৈশিষ্ট্যগুলিকে পছন্দ করি তবে আপনি যখন জোর দিয়ে বলতে চান যে কোনওself কিছু সেট করার ক্ষেত্রে অবজেক্টটি সংশোধন করা ছাড়াও পার্শ্ব প্রতিক্রিয়া রয়েছে , তখন সুস্পষ্ট সেটটারগুলি সহায়ক হতে পারে। উদাহরণস্বরূপ, user.email = "..."দেখে মনে হচ্ছে না এটি কোনও ব্যতিক্রম বাড়াতে পারে কারণ এটি দেখতে কেবল কোনও বৈশিষ্ট্য নির্ধারণের মতো দেখায়, যেখানে user.set_email("...")এটি পরিষ্কার করে দেয় যে ব্যতিক্রমগুলির মতো পার্শ্ব প্রতিক্রিয়াও থাকতে পারে।
bluenote10

65

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

আমি আসলে আলাদা আইডিয়া ব্যবহার করতে পছন্দ করি, যা বন্ধ হিসাবে ব্যবহার করার জন্য কিছুটা জড়িত, তবে আপনার আরও জটিল ব্যবহারের ক্ষেত্রে যদি খুব সুন্দর হয়।

প্রথমে কিছুটা ব্যাকগ্রাউন্ড।

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

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অবজেক্টের __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] কোডটি বিশৃঙ্খল করে তোলে এটি অতিরিক্ত শব্দ।

আরেকটি বিরক্তি হ'ল আমাদের এখনও মান xএবং yমানগুলি শুরু করতে হবে __init__। (আচ্ছা, অবশ্যই আমরা এগুলি ব্যবহার করে যুক্ত করতে পারি 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]

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

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

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

আমার মনে আমরা সত্যিকার অর্থে যা চাই তা হ'ল নিম্নলিখিত প্রয়োজনীয়তাগুলি ক্যাপচার করে:

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

  • ব্যবহারকারীর ফাংশনটির অন্তর্নিহিত অতিরিক্ত ভেরিয়েবল সংজ্ঞায়িত করার প্রয়োজন নেই, সুতরাং আমাদের কোড __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

এবং তাই এগিয়ে।

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

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

আমরা কোনও সম্পত্তির ধারণাটি প্রতিস্থাপন করতে একটি নতুন অবজেক্ট তৈরি করি। অবজেক্টটির জন্য এটিতে পরিবর্তনশীল সেটটির মান সঞ্চয় করার উদ্দেশ্যে করা হয়, তবে কোডটিতে একটি হ্যান্ডেলও বজায় রাখে যে কীভাবে ডিফল্ট গণনা করতে হয় knows এর কাজটি হ'ল সেটটি সঞ্চয় করা 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কারণ Noneএটি একটি সত্যিকারের মূল্য হতে পারে এবং এটি আমাদের সেখানে একটি সত্যিকারের "কোন মূল্য নেই" তা ঘোষণা করার একটি পরিষ্কার উপায়ের অনুমতি দেয়। অন্য উপায়টি হ'ল কোনও প্রকারের প্রেরক el

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

class Example(object):

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

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

আসুন দিয়ে শুরু করা যাক।

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

def uberProperty(f):
    return UberProperty(f)

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

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

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শ্রেণীর শ্রেণীর কোনও বস্তুতে শ্রেণি তৈরি হওয়ার পরে সেই বস্তুটি ব্যবহারকারীর কাছে ব্যবহারের আগে ফেরত দেওয়ার আগে আমাদের কীভাবে প্রয়োজন তা ডেকেরেটর দ্বারা তৈরি দৃষ্টান্তটি গতিশীলভাবে বাঁধার কিছু উপায় । ওম, হ্যাঁ, এটি একটি __init__ফোন, বন্ধু।

আসুন আমরা কীভাবে আমাদের সন্ধানের ফলাফলটি প্রথম হতে চাই তা লিখি। আমরা 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__হিসাবে আমাদের সাজসজ্জা চালানো হয়েছে বলা হয়, তাই কেবল অবজেক্টের সন্ধান করা __dict__এবং বৈশিষ্ট্যের মান টাইপ হওয়া এমন কোনও বৈশিষ্ট্য আপডেট করতে হবে UberProperty

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

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এখানে। এটি হ'ল কারণ আমি এগুলি স্বয়ংক্রিয়ভাবে ফিরে আসার উপায়টিতে এখনও লিঙ্ক করি নি।

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

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

  • আমাদের নিশ্চিত করা দরকার যে উবারঅবজেক্টকে __init__সর্বদা সাবক্লাস দ্বারা ডাকা হয়।

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

      class Example(object):
          @uberProperty
          def x(self):
              ...
    
          y = x
  • আমাদের ডিফল্টরূপে e.xফিরে আসতে হবে e.x.getValue()

    • আমরা আসলে যা দেখব তা হ'ল এটি এমন একটি অঞ্চল যেখানে মডেল ব্যর্থ হয়।
    • দেখা যাচ্ছে যে মানটি পেতে আমাদের সর্বদা একটি ফাংশন কল ব্যবহার করা প্রয়োজন।
    • তবে আমরা এটিকে একটি নিয়মিত ফাংশন কলের মতো দেখতে এবং ব্যবহার করতে এড়াতে পারি e.x.getValue()। (আপনি যদি ইতিমধ্যে এটি স্থির না করে থাকেন তবে এটি করা সুস্পষ্ট)
  • আমাদের e.x directlyযেমন প্রয়োজন সেটিং সমর্থন করা প্রয়োজন e.x = <newvalue>। আমরা এটি প্যারেন্ট ক্লাসেও করতে পারি, তবে __init__এটি পরিচালনা করতে আমাদের কোড আপডেট করতে হবে update

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

কোডটি এখন অবধি বিদ্যমান's

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] আমি এখনও পিছিয়ে থাকতে পারি এই ক্ষেত্রে এখনও আছে কিনা।


53
হ্যাঁ, এটি 'tldr'। আপনি এখানে কি করার চেষ্টা করছেন দয়া করে সংক্ষেপে বলতে পারেন?
পুলি

9
@ অ্যাডাম return self.x or self.defaultX()এটি বিপজ্জনক কোড। তখন কি হয় self.x == 0?
কেলি টমাস

এফওয়াইআই, আপনি এটি তৈরি করতে পারেন যাতে আপনি গেটারকে পরামিতি করতে পারেন, ধরণের। এটি ভেরিয়েবলটিকে একটি কাস্টম শ্রেণি তৈরি করার সাথে জড়িত, যার মধ্যে আপনি __getitem__পদ্ধতিটি ওভাররাইড করেছেন । এটি যদিও অদ্ভুত হবে কারণ আপনি তখন সম্পূর্ণরূপে অ-মানক অজগর রাখতেন।
হবে

2
@ কেলি থমাস কেবল উদাহরণটি সহজ রাখার চেষ্টা করছেন। এটি সঠিকভাবে করার জন্য আপনাকে সম্পূর্ণরূপে এক্স ডিকার এন্ট্রি তৈরি এবং মুছতে হবে , কারণ কোনও মানও নির্দিষ্টভাবে সেট করা থাকতে পারে। তবে হ্যাঁ, আপনি একেবারেই ঠিক বলেছেন এটি একটি উত্পাদন ব্যবহারের ক্ষেত্রে আপনাকে বিবেচনা করা উচিত to
অ্যাডাম দোনাহু

জাভা-মত getters আপনাকে ঠিক একই গণনা করতে দেয়, তাই না?
কেইড

26

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

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

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

আপনি গেটর এবং সেটার ফাংশনগুলিকে C.p.fgetএবং হিসাবে অ্যাক্সেস করতে পারেন C.p.fsetতবে আপনি তাদের প্রসারিত করতে সাধারণ পদ্ধতির উত্তরাধিকার (যেমন সুপার) সুবিধাদি সহজেই ব্যবহার করতে পারবেন না। সুপারের জটিলতাগুলিতে কিছু খননের পরে, আপনি সত্যই এইভাবে সুপার ব্যবহার করতে পারেন :

# 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)

সুপার () ব্যবহার করা তবে বেশ জঘন্য, যেহেতু সম্পত্তিটিকে নতুন করে সংজ্ঞায়িত করতে হবে এবং আপনাকে পি এর আনবাউন্ড অনুলিপি পেতে সামান্য পাল্টা স্বজ্ঞাত সুপার (সিএসএস, ক্লস) প্রক্রিয়াটি ব্যবহার করতে হবে।


20

বৈশিষ্ট্যগুলি ব্যবহার করা আমার কাছে আরও স্বজ্ঞাত এবং বেশিরভাগ কোডের সাথে আরও ভাল ফিট করে।

তুলনা

o.x = 5
ox = o.x

বনাম

o.setX(5)
ox = o.getX()

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


12

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

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.

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

আমি গেটর এবং সেটটারগুলি ব্যবহার এড়াতে চাই:

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

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

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

বা একটি সাদৃশ্য অ্যাকাউন্ট.সেভ পদ্ধতি।

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


3
@ user2239734 আমি মনে করি আপনি সম্পত্তি সম্পর্কিত ধারণাটি ভুল বুঝেছেন। যদিও সম্পত্তিটি সেট করার সময় আপনি মানটি বৈধ করতে পারেন, এটি করার দরকার নেই। আপনার validate()ক্লাসে বৈশিষ্ট্য এবং পদ্ধতি দুটি থাকতে পারে । কোনও সম্পত্তি সহজেই ব্যবহৃত হয় যখন আপনার কোনও সাধারণ obj.x = yকার্যভারের পিছনে একটি জটিল যুক্তি থাকে এবং যুক্তিটি কী তা নির্ভর করে।
জাউর নাসিভভ

12

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

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

পাইথনে, লোকেরা আসলে সেই ধরণের ওভারহেডের যত্ন করে, যাতে আপনি নিম্নলিখিত অনুশীলনটি গ্রহণ করতে পারেন:

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

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

1
ওহ না দুঃখিত। এটির মতো শোনাচ্ছে যে এই নম্বরটি ব্যাকআপ করার জন্য আমার কিছু অধ্যয়ন আছে তবে আমি কেবল এটি "বেশিরভাগ সময়" হিসাবে বুঝি।
ফুলমিকোটন

7
এটি লোকেদের ওভারহেডের প্রতি যত্নশীল নয়, পাইথনে আপনি ক্লায়েন্ট কোডটি পরিবর্তন না করেই অ্যাক্সেসর পদ্ধতিতে সরাসরি প্রবেশাধিকার থেকে পরিবর্তন করতে পারেন, তাই প্রথমে সরাসরি সম্পত্তি প্রকাশ করে আপনার হারাতে হবে না।
নিল জি

10

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

  • বৈধকরণ
  • তথ্য পরিবর্তন করুন
  • হাঁসের ধরণ (অন্য ধরণের কোরেস টাইপ)

এই উপহার একটি স্মার্ট লুকান বাস্তবায়ন বিবরণ এবং রেগুলার এক্সপ্রেশন, টাইপ কাস্ট করে দেখুন .. ব্লক, গবেষকেরা বা নির্ণিত মান ব্যতীত মত কোড cruft উপায়।

সাধারণভাবে কোনও বস্তুতে সিআরইউডি করা প্রায়শই সম্পূর্ণ জাগতিক হতে পারে তবে এমন ডেটার উদাহরণ বিবেচনা করুন যা কোনও সম্পর্কযুক্ত ডাটাবেসে অব্যাহত থাকবে। ওআরএম কোনও সম্পত্তি শ্রেণিতে সংজ্ঞায়িত fget, fset, fdel কে আবদ্ধ পদ্ধতিতে নির্দিষ্ট এসকিউএল স্থানীয় ভাষাগুলির বাস্তবায়ন বিবরণ আড়াল করতে পারে যা অ্যালিফ .. অন্য সিঁদাগুলি যা ওও কোডটিতে এতই কুৎসিত - সাধারণ এবং উদ্ভাসিত মার্জিত self.variable = somethingএবং বিকাশকারী জন্য বিবরণ নিবারণ ব্যবহার ORM।

যদি কেউ সম্পত্তিটিকে কেবল কোনও বন্ধন এবং শৃঙ্খলাভুক্ত ভাষার (যেমন জাভা) কিছু বিদ্রূপযুক্ত ভাবেন তবে তারা বর্ণনাকারীর বিন্দুটি অনুপস্থিত missing


6

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

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

def set_my_attr(self, value):
    ...

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

1) অজগর একটি বিদ্যমান বস্তুর জন্য নতুন বৈশিষ্ট্য তৈরি করতে দেয় allows এটি নিম্নলিখিত ভুল ছাপকে ট্র্যাক করা খুব কঠিন করে তোলে:

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()

5

উভয় @property এবং traditionalতিহ্যগত getters এবং সেটার তাদের সুবিধা আছে। এটি আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে।

এর সুবিধা @property

  • ডেটা অ্যাক্সেসের বাস্তবায়ন পরিবর্তন করার সময় আপনাকে ইন্টারফেসটি পরিবর্তন করতে হবে না। যখন আপনার প্রকল্পটি ছোট হয়, আপনি সম্ভবত কোনও শ্রেণীর সদস্যকে অ্যাক্সেস করার জন্য সরাসরি অ্যাট্রিবিউট অ্যাক্সেস ব্যবহার করতে চান। উদাহরণস্বরূপ, ধরা যাক আপনার একটি অবজেক্ট রয়েছেfoo কাছে টাইপের রয়েছে Fooযার একটি সদস্য রয়েছে num। তারপরে আপনি কেবল এই সদস্যটির সাথে পেতে পারেন num = foo.num। আপনার প্রকল্পটি বাড়ার সাথে সাথে আপনি অনুভব করতে পারেন যে সরল বৈশিষ্ট্য অ্যাক্সেসের জন্য কিছু চেক বা ডিবাগ হওয়া দরকার। তারপরে আপনি এটি একটি অভ্যন্তর দিয়ে করতে পারেন@property ক্লাসের । ডেটা অ্যাক্সেস ইন্টারফেস একই থাকে যাতে ক্লায়েন্ট কোড সংশোধন করার প্রয়োজন হয় না।

    পিইপি -8 থেকে উদ্ধৃত :

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

  • @propertyপাইথনে ডেটা অ্যাক্সেসের জন্য ব্যবহার হিসাবে বিবেচিত Pythonic :

    • এটি পাইথন (জাভা নয়) প্রোগ্রামার হিসাবে আপনার স্ব-সনাক্তকরণকে শক্তিশালী করতে পারে।

    • এটি যদি আপনার ইন্টারভিউয়ার জাভা-স্টাইলের গেটার এবং সেটটারদের বিরোধী নিদর্শন বলে মনে করে তবে এটি আপনার কাজের সাক্ষাত্কারে সহায়তা করতে পারে ।

Traditionalতিহ্যবাহী গেটার এবং সেটারদের সুবিধা

  • Attribতিহ্যবাহী গেটার্স এবং সেটটারগুলি সাধারণ অ্যাট্রিবিউটের অ্যাক্সেসের চেয়ে আরও জটিল ডেটা অ্যাক্সেসের অনুমতি দেয়। উদাহরণস্বরূপ, আপনি যখন কোনও শ্রেণীর সদস্য স্থাপন করছেন, কখনও কখনও আপনার কাছে একটি পতাকা লাগানো থাকে যা নির্দেশ করে যে কোনও জায়গাটি নিখুঁত না লাগলেও আপনি এই অপারেশনটি জোর করতে চান। সরাসরি সদস্যের অ্যাক্সেসের মতো কীভাবে বৃদ্ধি করা যায় তা স্পষ্ট নয় foo.num = num, আপনি অতিরিক্ত forceপ্যারামিটার দিয়ে সহজেই আপনার traditionalতিহ্যবাহী সেটারটিকে বাড়িয়ে তুলতে পারেন :

    def Foo:
        def set_num(self, num, force=False):
            ...
  • Ditionতিহ্যবাহী গেটার্স এবং সেটটারগুলি এটিকে স্পষ্ট করে তোলে যে কোনও শ্রেণীর সদস্য অ্যাক্সেস কোনও পদ্ধতির মাধ্যমে। এর অর্থ:

    • ফলস্বরূপ আপনি যা পান তা ক্লাসের মধ্যে ঠিক কীভাবে সঞ্চিত থাকে তার মতো নাও হতে পারে।

    • এমনকি যদি অ্যাক্সেসটিকে কোনও সাধারণ বৈশিষ্ট্য অ্যাক্সেসের মতো মনে হয়, তবে পারফরম্যান্সটি এ থেকে অনেক বেশি পরিবর্তিত হতে পারে।

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

  • @ নীলেনমারাইস এবং এই পোস্টে উল্লিখিত হিসাবে , সাবক্লাসে traditional তিহ্যবাহী গেটার এবং সেটটারগুলি বাড়ানো সম্পত্তি বাড়ানোর চেয়ে সহজ is

  • Ditionতিহ্যবাহী গেটার্স এবং সেটারগুলি বিভিন্ন ভাষায় দীর্ঘকাল ধরে ব্যাপকভাবে ব্যবহৃত হয়ে আসছে। আপনার দলে যদি বিভিন্ন ব্যাকগ্রাউন্ডের লোক থাকে তবে তারা তার চেয়ে বেশি পরিচিত দেখাচ্ছে @property। এছাড়াও, আপনার প্রকল্পটি বাড়ার সাথে সাথে, যদি আপনার পাইথন থেকে অন্য কোনও ভাষায় মাইগ্রেশন করার প্রয়োজন হতে পারে তবে @propertytraditionalতিহ্যবাহী গেটরস এবং সেটারগুলি ব্যবহার করে স্থানান্তরকে সহজতর করা হবে।

আদেশ সহকারে

  • আমরাও @propertyনা ঐতিহ্যগত getters এবং setters বর্গ সদস্য ব্যক্তিগত তোলে, এমনকি যদি আপনি তার নাম আগে ডবল আন্ডারস্কোর ব্যবহার করুন:

    class Foo:
        def __init__(self):
            self.__num = 0
    
        @property
        def num(self):
            return self.__num
    
        @num.setter
        def num(self, num):
            self.__num = num
    
        def get_num(self):
            return self.__num
    
        def set_num(self, num):
            self.__num = num
    
    foo = Foo()
    print(foo.num)          # output: 0
    print(foo.get_num())    # output: 0
    print(foo._Foo__num)    # output: 0

2

এখানে "কার্যকর পাইথন: উন্নত পাইথন লেখার 90 টি নির্দিষ্ট উপায়" (আশ্চর্যজনক বইটি highly

মনে রাখার মতো ঘটনা

Public সাধারণ জনসাধারণের বৈশিষ্ট্যগুলি ব্যবহার করে নতুন শ্রেণীর ইন্টারফেসগুলি সংজ্ঞায়িত করুন এবং সেটার এবং গেটর পদ্ধতিগুলি সংজ্ঞায়িত করা এড়ান।

P প্রয়োজনে আপনার অবজেক্টগুলিতে অ্যাট্রিবিউটগুলি অ্যাক্সেস পাওয়া গেলে বিশেষ আচরণের সংজ্ঞা দিতে @ প্রপার্টি ব্যবহার করুন।

Least কমপক্ষে অবাক হওয়ার নিয়মটি অনুসরণ করুন এবং আপনার @ প্রোপার্টি পদ্ধতিতে বিজোড় পার্শ্ব প্রতিক্রিয়া এড়ান।

P নিশ্চিত করুন যে @ প্রপার্টি পদ্ধতিগুলি দ্রুত; ধীর বা জটিল কাজের জন্য - বিশেষত I / O জড়িত বা পার্শ্ব প্রতিক্রিয়া সৃষ্টি করে — পরিবর্তে সাধারণ পদ্ধতি ব্যবহার করুন।

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

আমি বিশেষত @ প্রপার্টি পছন্দ করি কারণ এটি আপনাকে সময়ের সাথে আরও ভাল ডেটা মডেলের দিকে বাড়তি অগ্রগতি করতে দেয়।
@ প্রপার্টি হ'ল এমন একটি সরঞ্জাম যা আপনাকে রিয়েল-ওয়ার্ল্ড কোডে আসবে এমন সমস্যাগুলির সমাধান করতে সহায়তা করার একটি সরঞ্জাম। এটি অতিরিক্ত ব্যবহার করবেন না। আপনি যখন নিজেকে বারবার @ প্রপার্টি পদ্ধতিগুলি প্রসারিত করতে দেখেন তখন সম্ভবত আপনার কোডটির দুর্বল নকশাকে আরও প্রশস্ত করার পরিবর্তে আপনার ক্লাসটি রিফ্যাক্টর করার সময় এসেছে।

Existing বিদ্যমান উদাহরণটি নতুন কার্যকারিতা দেওয়ার জন্য @ প্রপার্টি ব্যবহার করুন।

@ @ প্রোপার্টি ব্যবহার করে আরও ভাল ডেটা মডেলগুলির দিকে বাড়তি অগ্রগতি করুন।

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

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