একটি মেটাক্লাস ব্যবহার করুন
আমি পদ্ধতি # 2 সুপারিশ করব , তবে আপনি বেস ক্লাসের চেয়ে মেটাক্লাস ব্যবহার করা ভাল । এখানে একটি নমুনা বাস্তবায়ন:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Logger(object):
__metaclass__ = Singleton
বা পাইথন 3 এ
class Logger(metaclass=Singleton):
pass
__init__
ক্লাসটি ডাকা হলে প্রতিবার চালাতে চাইলে অ্যাড করুন
else:
cls._instances[cls].__init__(*args, **kwargs)
থেকে if
বিবৃতি Singleton.__call__
।
মেটাক্লাস সম্পর্কে কয়েকটি শব্দ। একটি মেটাক্লাস একটি শ্রেণীর শ্রেণি ; অর্থাৎ, একটি বর্গ তার মেটাক্লাসের উদাহরণ । পাইথনের সাথে আপনি কোনও বস্তুর মেটাক্লাস খুঁজে পান type(obj)
। সাধারন নতুন স্টাইলের শ্রেণীর ধরনের type
। Logger
উপরের কোডটিতে টাইপ হবে class 'your_module.Singleton'
, ঠিক যেমন (কেবল) উদাহরণ Logger
টাইপ হবে class 'your_module.Logger'
। যখন আপনার সাথে এটির কল Logger()
, পাইথন প্রথম ক্লাসের অধীনে একটি ক্লাস জিজ্ঞেস Logger
, Singleton
, কি করতে হবে, যার ফলে উদাহরণস্বরূপ সৃষ্টি প্রাক empted হবে। এই প্রক্রিয়া পাইথন একটি বর্গ কি কল করে না জিজ্ঞাসা হিসাবে একই __getattr__
যখন আপনি করছেন তা এমন সব গুণাবলীর এক রেফারেন্স myclass.attribute
।
একটি মেটাক্লাস মূলত সিদ্ধান্ত নেয় যে কোনও শ্রেণীর সংজ্ঞা কী এবং কীভাবে সেই সংজ্ঞাটি প্রয়োগ করা যায় implement উদাহরণস্বরূপ দেখুন http://code.activestate.com/recines/498149/ , যা মূলত struct
মেটাক্লাস ব্যবহার করে পাইথনে সি-স্টাইল গুলি পুনরায় তৈরি করে। থ্রেডটি मेटाটাক্লাসগুলির জন্য কিছু (কংক্রিট) ব্যবহারের ক্ষেত্রে কী কী? এছাড়াও কিছু উদাহরণ সরবরাহ করে, তারা সাধারণত ঘোষিত প্রোগ্রামিংয়ের সাথে সম্পর্কিত বলে মনে হয়, বিশেষত ওআরএম-তে ব্যবহৃত হিসাবে।
এই পরিস্থিতিতে আপনি যদি আপনার পদ্ধতি # 2 ব্যবহার করেন এবং একটি সাবক্লাস কোনও __new__
পদ্ধতি সংজ্ঞায়িত করে তবে আপনি যতবার কল করবেন ততক্ষণে এটি কার্যকর করা হবে SubClassOfSingleton()
- কারণ সঞ্চিত উদাহরণটি ফিরে আসে এমন পদ্ধতিতে কল করার জন্য এটি দায়বদ্ধ। একটি মেটাক্লাসের সাহায্যে এটি কেবল একবার কল করা হবে , যখন একমাত্র উদাহরণ তৈরি করা হবে। ক্লাসটি বলতে কী বোঝায় তা আপনি কাস্টমাইজ করতে চান , যা এটি টাইপ দ্বারা স্থির হয়।
সাধারণভাবে, একটি সিঙ্গলটন বাস্তবায়নের জন্য একটি মেটাক্লাস ব্যবহার করা বোধগম্য । একটি সিঙ্গলটন বিশেষ কারণ শুধুমাত্র একবার তৈরি করা হয় , এবং একটি ক্লাস তৈরির পদ্ধতিটি মেটাকগ্লাসকেই আপনি অনুকূলিত করেন । আপনি যদি অন্যভাবে সিঙ্গলটন শ্রেণির সংজ্ঞাটি কাস্টমাইজ করতে চান তবে একটি মেটাক্লাস ব্যবহার আপনাকে আরও নিয়ন্ত্রণ দেয় ।
আপনার সিঙ্গেলটনের একাধিক উত্তরাধিকারের প্রয়োজন হবে না (কারণ মেটাক্লাস একটি বেস শ্রেণি নয়) তবে একাধিক উত্তরাধিকার ব্যবহার করে তৈরি শ্রেণীর সাবক্লাসগুলির জন্য আপনাকে নিশ্চিত করতে হবে যে মেটাক্লাসের সাথে সিঙ্গেলটন শ্রেণি প্রথম / বামতম এক যা পুনরায় সংজ্ঞায়িত করে __call__
এটি খুব সমস্যা হওয়ার সম্ভাবনা নেই। উদাহরণস্বরূপ ডক উদাহরণস্বরূপ এর নামস্থানে নেই তাই এটি দুর্ঘটনাক্রমে এটি ওভাররাইট হবে না।
আপনি আরও শুনতে পাবেন যে সিঙ্গলটন প্যাটার্নটি "একক দায়িত্বের নীতিমালা" লঙ্ঘন করে - প্রতিটি শ্রেণীর কেবল একটি কাজ করা উচিত । আপনাকে অন্য পরিবর্তন করার প্রয়োজন হলে কোডটি একটি জিনিস গণ্ডগোলের বিষয়ে আপনাকে উদ্বিগ্ন হওয়ার দরকার নেই, কারণ সেগুলি পৃথক এবং আবদ্ধ। মেটাক্লাস বাস্তবায়ন এই পরীক্ষায় পাস করে । মেটাক্লাসটি প্যাটার্নটি প্রয়োগের জন্য দায়ী এবং তৈরি ক্লাস এবং সাবক্লাসগুলি সচেতন হওয়া উচিত নয় যে তারা সিঙ্গেলন । # 1 পদ্ধতিটি এই পরীক্ষায় ব্যর্থ হয়েছে, যেমন আপনি উল্লেখ করেছেন যে "মাই ক্লাস নিজেই একটি ফাংশন, কোনও শ্রেণি নয়, সুতরাং আপনি এটি থেকে শ্রেণি পদ্ধতিতে কল করতে পারবেন না।"
পাইথন 2 এবং 3 সামঞ্জস্যপূর্ণ সংস্করণ
পাইথন 2 এবং 3 উভয় ক্ষেত্রে কাজ করে এমন কিছু লেখার জন্য আরও জটিল জটিল স্কিম ব্যবহার করা দরকার। যেহেতু মেটাক্লাসগুলি সাধারণত ধরণের সাবক্লাস হয় তাই এটি রানাকালীন type
সময়ে একটি মধ্যস্থতাকার বেস ক্লাসটিকে তার মেটাক্লাস হিসাবে গতিশীলভাবে তৈরি করতে এবং তারপরে পাবলিক বেস শ্রেণির বেসক্লাস হিসাবে ব্যবহার করা সম্ভব Singleton
। এটি করার চেয়ে ব্যাখ্যা করা আরও শক্ত, পরবর্তী চিত্রিত:
# works in Python 2 & 3
class _Singleton(type):
""" A metaclass that creates a Singleton base class when called. """
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Singleton(_Singleton('SingletonMeta', (object,), {})): pass
class Logger(Singleton):
pass
এই পদ্ধতির একটি হাস্যকর দিক হ'ল এটি একটি মেটাক্লাস বাস্তবায়নের জন্য সাবক্লাসিং ব্যবহার করছে। একটি সম্ভাব্য সুবিধা হ'ল শুদ্ধ মেটাক্লাসের বিপরীতে isinstance(inst, Singleton)
ফিরে আসবে True
।
সংশোধণী
অন্য বিষয়ে, আপনি সম্ভবত এটি ইতিমধ্যে লক্ষ্য করেছেন, কিন্তু আপনার মূল পোস্টে বেস শ্রেণীর প্রয়োগটি ভুল। _instances
চাহিদা করা বর্গ উপর রেফারেন্সড , আপনি ব্যবহার করতে হবে super()
বা তুমি recursing , এবং __new__
আপনি করতে হবে যে আসলে একটি স্ট্যাটিক পদ্ধতি থেকে বর্গ পাস , না একটি বর্গ পদ্ধতি হিসাবে প্রকৃত শ্রেণী সৃষ্টি করা হয়েছে এখনো যখন এটি বলা হয়. এই সমস্ত জিনিস একটি মেটাক্লাস বাস্তবায়নের জন্যও সত্য হবে।
class Singleton(object):
_instances = {}
def __new__(class_, *args, **kwargs):
if class_ not in class_._instances:
class_._instances[class_] = super(Singleton, class_).__new__(class_, *args, **kwargs)
return class_._instances[class_]
class MyClass(Singleton):
pass
c = MyClass()
সাজসজ্জা এক ক্লাস রিটার্নিং
আমি মূলত একটি মন্তব্য লিখছিলাম তবে এটি অনেক দীর্ঘ ছিল, তাই আমি এটি এখানে যুক্ত করব। অন্যান্য ডেকরেটার সংস্করণের চেয়ে # 4 পদ্ধতিটি আরও ভাল তবে এটি একটি সিঙ্গলটনের জন্য প্রয়োজনের চেয়ে বেশি কোড এবং এটি কী করে তা পরিষ্কার নয়।
ক্লাসটি হ'ল মূল সমস্যাটি হ'ল এটি নিজস্ব বেস ক্লাস। প্রথমত, ক্লাসটি প্রায় একইরকম বর্গের একই নাম যা কেবল তার __class__
বৈশিষ্ট্যে উপস্থিত রয়েছে তার একটি সাবক্লাস হওয়া কি অদ্ভুত নয় ? এটাও এর মানে হল যে আপনি সংজ্ঞায়িত করতে পারবে না কোনো পদ্ধতি যে তাদের বেস বর্গ উপর একই নামের পদ্ধতি কল সঙ্গে super()
, কারণ তারা recurse হবে। এর অর্থ আপনার ক্লাসটি অনুকূলিতকরণ করতে পারে না __new__
, এবং যে কোনও ক্লাসের প্রয়োজন __init__
তাদের থেকে নেওয়া যাবে না ive
সিঙ্গলটন প্যাটার্নটি কখন ব্যবহার করবেন
আপনার ব্যবহারের ক্ষেত্রে সিঙ্গলটন ব্যবহার করতে চাওয়ার অন্যতম সেরা উদাহরণ । আপনি একটি মন্তব্যে বলছেন "আমার কাছে লগিং সর্বদা সিঙ্গলটনের প্রাকৃতিক প্রার্থী বলে মনে হয়।" আপনি একেবারে ঠিক বলেছেন ।
লোকেরা যখন বলে যে সিলেটলেটগুলি খারাপ, সর্বাধিক সাধারণ কারণ হ'ল তারা নিখরচায় ভাগ করা অবস্থা । বৈশ্বিক ভেরিয়েবল এবং শীর্ষ-স্তরের মডিউল আমদানিগুলি সুস্পষ্ট ভাগ করে নেওয়ার স্থিতি সহ, অন্যান্য অবজেক্টগুলি সাধারণত পাস করা হয় an এটি দুটি ব্যতিক্রম ব্যতীত একটি ভাল পয়েন্ট ।
প্রথম এবং এক যা বিভিন্ন স্থানে উল্লেখ করা হয়, তা হ'ল সিলেটনের ধ্রুবক থাকে । বিশ্বব্যাপী ধ্রুবকগুলির ব্যবহার, বিশেষত এনামগুলিকে ব্যাপকভাবে গ্রহণ করা হয় এবং এটি বুদ্ধিমান হিসাবে বিবেচিত হয় কারণ যে কোনও বিষয়ই হোক না কেন ব্যবহারকারীরা তাদের কোনও অন্য ব্যবহারকারীর জন্য এই গোলযোগ করতে পারবেন না । এটি একটি ধ্রুবক সিঙ্গলটনের জন্যও সমান সত্য।
দ্বিতীয় ব্যতিক্রম, যা কম উল্লেখ করা হয় তার বিপরীত - যখন সিঙ্গলটন কেবলমাত্র একটি ডেটা সিঙ্ক হয় , কোনও ডেটা উত্স নয় (প্রত্যক্ষ বা পরোক্ষভাবে)। এই কারণেই লগাররা সিলেটলেটের জন্য "প্রাকৃতিক" ব্যবহারের মতো বোধ করে। যেহেতু বিভিন্ন ব্যবহারকারী লগারগুলিকে অন্য ব্যবহারকারীদের যত্ন নেবেন সেভাবে পরিবর্তন করছেন না, আসলে ভাগ করে নেওয়া স্থিতি নেই । এটি সিঙ্গেলটন প্যাটার্নের বিরুদ্ধে প্রাথমিক তর্কটিকে তুচ্ছ করে এবং কাজের জন্য তাদের ব্যবহারের সহজতার কারণে তাদের যুক্তিসঙ্গত পছন্দ করে তোলে ।
Http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html- এর একটি উদ্ধৃতি এখানে রয়েছে :
এখন, এখানে এক ধরণের সিঙ্গল আছে যা ঠিক আছে। এটি এমন একক সিঙ্গলটন যেখানে পৌঁছনযোগ্য সমস্ত বস্তু অপরিবর্তনীয়। সমস্ত বস্তু যদি অবিচল থাকে তবে সিঙ্গেলনের কোনও বৈশ্বিক অবস্থা নেই, কারণ সবকিছু অবিচ্ছিন্ন। তবে এই ধরণের সিঙ্গলটনকে পরিবর্তনীয় স্থানে রূপান্তর করা এত সহজ, এটি খুব পিচ্ছিল opeাল। অতএব, আমি এই সিঙ্গলটনের বিরুদ্ধেও আছি, এগুলি খারাপ হওয়ার কারণে নয়, কারণ খারাপ হওয়া তাদের পক্ষে খুব সহজ। (পার্শ্ব দ্রষ্টব্য হিসাবে জাভা গণনাটি কেবল এই ধরণের সিলেটলেট let
অন্যান্য ধরণের সিঙ্গলেটনগুলি, যা আধা-গ্রহণযোগ্য তা হ'ল যা আপনার কোড প্রয়োগের ক্ষেত্রে প্রভাব ফেলবে না, তাদের কোনও "পার্শ্ব প্রতিক্রিয়া" নেই। লগিং নিখুঁত উদাহরণ। এটি সিলেটলেটস এবং গ্লোবাল স্টেট দিয়ে লোড হয়। এটি গ্রহণযোগ্য (যেমন এতে আপনাকে আঘাত করবে না) কারণ আপনার অ্যাপ্লিকেশন কোনও প্রদত্ত লগার সক্ষম কিনা তা কোনও আলাদা আচরণ করে না। এখানে তথ্যগুলি একপথে প্রবাহিত হয়: আপনার অ্যাপ্লিকেশন থেকে লগারে। এমনকি চিন্তিত লগারগুলি বিশ্বরাষ্ট্র হিসাবে যেহেতু আপনার অ্যাপ্লিকেশনটিতে লগার থেকে কোনও তথ্য প্রবাহিত হয় না, লগারগুলি গ্রহণযোগ্য। আপনি যদি এখনও পরীক্ষা করতে চান যে কোনও কিছু লগ হচ্ছে, তবে সাধারণভাবে লোগারগুলি পুরো রাজ্যে থাকা সত্ত্বেও ক্ষতিকারক নয় You
foo.x
বা আপনি যদিFoo.x
পরিবর্তে জেদ করেনFoo().x
); শ্রেণীর বৈশিষ্ট্য এবং স্থির / শ্রেণি পদ্ধতি (Foo.x
) ব্যবহার করুন।