[ টিএল; ডিআর? আপনি একটি কোড উদাহরণের জন্য শেষ দিকে যেতে পারেন ]]
আমি আসলে আলাদা আইডিয়া ব্যবহার করতে পছন্দ করি, যা বন্ধ হিসাবে ব্যবহার করার জন্য কিছুটা জড়িত, তবে আপনার আরও জটিল ব্যবহারের ক্ষেত্রে যদি খুব সুন্দর হয়।
প্রথমে কিছুটা ব্যাকগ্রাউন্ড।
বৈশিষ্ট্যগুলি কার্যকর হয় যাতে তারা আমাদের প্রোগ্রামিং পদ্ধতিতে সেটিং এবং মান উভয়ই পরিচালনা করতে দেয় তবে তবুও বৈশিষ্ট্যগুলিকে বৈশিষ্ট্য হিসাবে অ্যাক্সেস করার অনুমতি দেয়। আমরা 'গানে' কে 'গণনা' (মূলত) রূপান্তর করতে পারি এবং আমরা 'সেট'গুলিকে' ইভেন্টে 'রূপান্তর করতে পারি। সুতরাং আসুন আমরা আমাদের নীচের ক্লাসটি বলতে পারি, যা আমি জাভা-এর মত গেটার এবং সেটটারগুলির সাথে কোড করেছি।
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] আমি এখনও পিছিয়ে থাকতে পারি এই ক্ষেত্রে এখনও আছে কিনা।