একটি "শ্রেণিবদ্ধ" এবং একটি মেটাক্লাস পদ্ধতির মধ্যে পার্থক্য কী?


12

পাইথনে, আমি ডেকরেটার ব্যবহার করে একটি শ্রেণিবদ্ধ পদ্ধতি তৈরি করতে পারি @classmethod:

>>> class C:
...     @classmethod
...     def f(cls):
...             print(f'f called with cls={cls}')
...
>>> C.f()
f called with cls=<class '__main__.C'>

বিকল্পভাবে, আমি একটি মেটাক্লাসে একটি সাধারণ (উদাহরণ) পদ্ধতি ব্যবহার করতে পারি:

>>> class M(type):
...     def f(cls):
...             print(f'f called with cls={cls}')
...
>>> class C(metaclass=M):
...     pass
...
>>> C.f()
f called with cls=<class '__main__.C'>

এর আউটপুট দ্বারা প্রদর্শিত হিসাবে C.f(), এই দুটি পদ্ধতির অনুরূপ কার্যকারিতা সরবরাহ করে।

@classmethodএকটি মেটাক্লাসে একটি সাধারণ পদ্ধতি ব্যবহার এবং ব্যবহারের মধ্যে পার্থক্যগুলি কী ?

উত্তর:


5

ক্লাসগুলি একটি মেটাক্লাসের উদাহরণ হিসাবে, এটি অপ্রত্যাশিত নয় যে মেটাক্লাসের একটি "উদাহরণ পদ্ধতি" শ্রেণীবদ্ধের মতো আচরণ করবে।

তবে, হ্যাঁ, পার্থক্য রয়েছে - এবং এর মধ্যে কিছুগুলি শব্দার্থবিজ্ঞানের চেয়ে বেশি:

  1. সর্বাধিক গুরুত্বপূর্ণ পার্থক্যটি হ'ল মেটাক্লাসের কোনও পদ্ধতি কোনও শ্রেণীর উদাহরণ থেকে "দৃশ্যমান" নয় । এটি ঘটে কারণ পাইথনে অ্যাট্রিবিউট অনুসন্ধান (সরল পদ্ধতিতে - বর্ণনাকারীরা অগ্রাধিকার নিতে পারে) উদাহরণটিতে কোনও বৈশিষ্ট্যের সন্ধান করুন - যদি উদাহরণটিতে উপস্থিত না থাকে, পাইথন তারপরে সেই উদাহরণটির শ্রেণিতে দেখায় এবং তারপরে অনুসন্ধান চালিয়ে যায় ক্লাসের superclasses, কিন্তু ক্লাসের ক্লাস করেন। পাইথন stdlib abc.ABCMeta.registerপদ্ধতিতে এই বৈশিষ্ট্যটি ব্যবহার করে । এই বৈশিষ্ট্যটি ভাল হিসাবে ব্যবহার করা যেতে পারে, কারণ শ্রেণীর সাথে সম্পর্কিত পদ্ধতিগুলি কোনও দ্বন্দ্ব ছাড়াই উদাহরণস্বরূপ বৈশিষ্ট্য হিসাবে পুনরায় ব্যবহার করা মুক্ত (তবে কোনও পদ্ধতি এখনও বিরোধে লিপ্ত হবে)।
  2. যদি আপনি বিভিন্ন শ্রেণী শ্রেণীবিন্যাসের আছে, এ সব এর সাথে সম্পর্কিত না - আরেকটি পার্থক্য, যদিও সুস্পষ্ট, একটি পদ্ধতি ঘোষিত যে ক্লাসের অধীনে একটি ক্লাস বিভিন্ন শ্রেণীর পাওয়া হতে পারে, অন্যথায় এর সাথে সম্পর্কিত নয় কি তারা সাথে মোকাবিলা কিন্তু সব শ্রেণীর জন্য কিছু সাধারণ বৈশিষ্ট্য চান , আপনাকে একটি মিক্সিন ক্লাস নিয়ে আসতে হবে, যে উভয় স্তরক্রমের ভিত্তি হিসাবে অন্তর্ভুক্ত করতে হবে (অ্যাপ্লিকেশন রেজিস্ট্রিতে সমস্ত শ্রেণি অন্তর্ভুক্ত করার জন্য বলুন)। (এনবি। মিশ্রণটি কখনও কখনও মেটাক্লাসের চেয়ে ভাল কল হতে পারে)
  3. একটি শ্রেণিবদ্ধ একটি বিশেষায়িত "শ্রেণিবদ্ধ" বা বস্তু, মেটাক্লাসের একটি পদ্ধতি একটি সাধারণ ফাংশন।

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

এটি বেশিরভাগ সময় ব্যবহারিক পার্থক্য তৈরি করে না, তবে আপনি যদি কোনও ক্রিয়াকলাপ হিসাবে পদ্ধতিটিতে অ্যাক্সেস চান, তবে এটিতে মেটাক্লাসের কোনও পদ্ধতির জন্য গতিগতভাবে ডিকোরিটার যুক্ত করার উদ্দেশ্যে বা অন্য কোনও, meta.methodফাংশনটি পুনরুদ্ধার করে, ব্যবহারের জন্য প্রস্তুত , যখন আপনাকে cls.my_classmethod.__func__ এটি একটি শ্রেণিবদ্ধ থেকে পুনরুদ্ধার করতে ব্যবহার করতে হয় (এবং তারপরে আপনাকে অন্য কোনও classmethodঅবজেক্ট তৈরি করতে হবে এবং এটিকে ফেরত দিতে হবে, যদি আপনি কিছু মোড়ানো করেন)।

মূলত, এটি 2 উদাহরণ:


class M1(type):
    def clsmethod1(cls):
        pass

class CLS1(metaclass=M1):
    pass

def runtime_wrap(cls, method_name, wrapper):
    mcls = type(cls)
    setattr(mcls, method_name,  wrapper(getatttr(mcls, method_name)))

def wrapper(classmethod):
    def new_method(cls):
        print("wrapper called")
        return classmethod(cls)
    return new_method

runtime_wrap(cls1, "clsmethod1", wrapper)

class CLS2:
    @classmethod
    def classmethod2(cls):
        pass

 def runtime_wrap2(cls, method_name, wrapper):
    setattr(cls, method_name,  classmethod(
                wrapper(getatttr(cls, method_name).__func__)
        )
    )

runtime_wrap2(cls1, "clsmethod1", wrapper)

অন্য কথায়: মেটাক্লাসে সংজ্ঞায়িত একটি পদ্ধতি উদাহরণ থেকে দৃশ্যমান এবং কোনও classmethodঅবজেক্টের গুরুত্বপূর্ণ পার্থক্য বাদে , রানটাইমের সময় অন্যান্য পার্থক্যগুলি অস্পষ্ট এবং অর্থহীন বলে মনে হয় - তবে এটি ঘটে কারণ ভাষাটিতে যাওয়ার দরকার নেই শ্রেণিবদ্ধদের জন্য বিশেষ বিধিবিধানের বাইরে: শ্রেণিবদ্ধকে ঘোষণা করার উভয় পদ্ধতিই ভাষার নকশা থেকে ফলস্বরূপ সম্ভব - একটি, কারণ যে কোনও শ্রেণি নিজেই একটি বস্তু এবং অন্যটি, অনেকের মধ্যেই সম্ভাবনা হিসাবে, বর্ণনাকারী প্রোটোকলের ব্যবহার যা কোনও ব্যক্তিকে একটি উদাহরণে এবং শ্রেণিতে অ্যাট্রিবিউট অ্যাক্সেস বিশেষায়িত করতে দেয়:

classmethodBuiltin নেটিভ কোড সংজ্ঞায়িত করা হয়, কিন্তু এটি শুধু বিশুদ্ধ পাইথন কোডেড হতে পারে এবং সঠিক একই ভাবে কাজ করবে। 5 লাইন শ্রেণির বেলো অবশ্যই classmethodবিল্ট-ইন @classmethod" at all (though distinguishable through introspection such as calls toআইসনস্ট্যান্স , and evenরেপ্রেসের সাথে কোনও রানটাইম পার্থক্য না করে সজ্জা হিসাবে ব্যবহার করা যেতে পারে ):


class myclassmethod:
    def __init__(self, func):
        self.__func__ = func
    def __get__(self, instance, owner):
        return lambda *args, **kw: self.__func__(owner, *args, **kw)

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


2

আপনি যখন প্রশ্নটিতে যেমনটি করেছেন ঠিক তখনই @classmethodবাক্যটি ব্যবহার করেন, এবং মেটাচ্লাসগুলি দেখতে দেখতে একই রকম হতে পারে তবে তাদের উদ্দেশ্য ভিন্ন different @classmethod"যুক্তিযুক্ত ইনজেকশন করা বর্গটি সাধারণত একটি উদাহরণ (অর্থাত্ একটি বিকল্প নির্মাণকারী) তৈরির জন্য ব্যবহৃত হয়। অন্যদিকে, মেটাচ্লাসগুলি সাধারণত শ্রেণি নিজেই সংশোধন করতে ব্যবহৃত হয় (যেমন জাজানো তার মডেল ডিএসএল দিয়ে কী করে)

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

প্রথম উদাহরণটি কিছুটা প্রসারিত করা যাক।

class C:
    @classmethod
    def f(cls):
        print(f'f called with cls={cls}')

পাইথন ডক্স থেকে ধার নেওয়া, উপরেরটি নীচের মতো কিছুতে প্রসারিত হবে:

class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"

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

    def __get__(self, obj, klass=None):
        if klass is None:
            klass = type(obj)
        def newfunc(*args):
            return self.f(klass, *args)
        return newfunc

class C:
    def f(cls):
        print(f'f called with cls={cls}')
    f = ClassMethod(f)

নোট কিভাবে __get__পারেন একটি দৃষ্টান্ত বা বর্গ (অথবা উভয়) সময় লাগতে পারে, এবং এইভাবে আপনি উভয় কি করতে পারেন C.fএবং C().f। এই ক্লাসের অধীনে একটি ক্লাস উদাহরণ দিতে যা নিক্ষেপ করা হবে অসদৃশ হয় AttributeErrorজন্য C().f

তদুপরি, মেটাক্লাস উদাহরণে এটি fবিদ্যমান নেই C.__dict__। বৈশিষ্ট্যটির fসাথে অনুসন্ধান করার সময় C.f, দোভাষী তার দিকে তাকান C.__dict__এবং তারপরে অনুসন্ধানে ব্যর্থ হওয়ার পরে, type(C).__dict__(যা হয় M.__dict__) তাকান। যদি আপনি নমনীয়তা ওভাররাইড করতে চান এই বিষয়টি পারে fমধ্যে C, যদিও আমার সন্দেহ কখনও ব্যবহারিক প্রয়োগের হবে।


0

আপনার উদাহরণে, পার্থক্যটি অন্য কয়েকটি শ্রেণিতে হবে যা তাদের মেটাক্লাস হিসাবে এম সেট করবে।

class M(type):
    def f(cls):
        pass

class C(metaclass=M):
    pass

class C2(metaclass=M):
    pass

C.f()
C2.f()
class M(type):
     pass

class C(metaclass=M):
     @classmethod
     def f(cls):
        pass

class C2(metaclass=M):
    pass

C.f()
# C2 does not have 'f'

এখানে মেটাক্লাসগুলি আরও রয়েছে মেটাক্লাসগুলির জন্য কিছু (কংক্রিট) ব্যবহারের ক্ষেত্রে কী কী?


0

@ ক্লাসমেডোথ এবং মেটাক্লাস উভয়ই আলাদা।

পাইথনের সমস্ত কিছুই একটি বস্তু। প্রতিটি জিনিস প্রতিটি জিনিস মানে।

মেটাক্লাস কী?

যেমনটি বলেছে প্রতিটি জিনিসই একটি বস্তু। ক্লাসগুলি হ'ল বস্তুগুলিতে ক্লাসগুলি হ'ল আনুষ্ঠানিকভাবে মেটা-ক্লাস নামে পরিচিত অন্যান্য রহস্যময় বস্তুর উদাহরণ। পাইথনে ডিফল্ট মেটাক্লাস নির্দিষ্ট না হলে "টাইপ" হয়

ডিফল্টরূপে নির্ধারিত সমস্ত শ্রেণি হ'ল ধরণের দৃষ্টান্ত।

ক্লাসগুলি মেটা-ক্লাসের উদাহরণ

স্মরণীয় আচরণ বোঝার জন্য কয়েকটি গুরুত্বপূর্ণ বিষয় হ'ল

  • ক্লাসগুলি মেটা ক্লাসের উদাহরণ হিসাবে।
  • প্রতিটি তাত্ক্ষণিক বস্তুর মতো, বস্তুগুলির (উদাহরণস্বরূপ) শ্রেণি থেকে তাদের বৈশিষ্ট্যগুলি পায়। ক্লাস মেটা-ক্লাস থেকে এর বৈশিষ্ট্যগুলি পাবে

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

class Meta(type):
    def foo(self):
        print(f'foo is called self={self}')
        print('{} is instance of {}: {}'.format(self, Meta, isinstance(self, Meta)))

class C(metaclass=Meta):
    pass

C.foo()

কোথায়,

  • ক্লাস সি ক্লাস মেটা উদাহরণ
  • "ক্লাস সি" ক্লাস অবজেক্ট যা "ক্লাস মেটা" এর উদাহরণ
  • অন্য কোনও অবজেক্টের মতো (উদাহরণস্বরূপ) "ক্লাস সি" এর বৈশিষ্ট্য / পদ্ধতিগুলি এর "শ্রেণি মেটা" শ্রেণিতে সংজ্ঞায়িত হয়েছে
  • সুতরাং, "সিফু ()" ডিকোডিং। "সি" হ'ল "মেটা" এর উদাহরণ এবং "ফু" হ'ল "মেটা" উদাহরণের মাধ্যমে "কল" যা "সি" হয় method
  • "Foo" পদ্ধতির প্রথম যুক্তি হল "শ্রেণীবদ্ধ" এর চেয়ে পৃথক শ্রেণীর নয়

আমরা "শ্রেণি সি" "ক্লাস মেটা" উদাহরণ হিসাবে যাচাই করতে পারি

  isinstance(C, Meta)

শ্রেণীবদ্ধ কী?

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

শ্রেণি পদ্ধতি যেমন শ্রেণিতে আবদ্ধ। এটি কমপক্ষে একটি যুক্তি নেয় যা উদাহরণ (স্ব) এর পরিবর্তে শ্রেণি নিজেই উল্লেখ করা হয়

যদি অন্তর্নির্মিত ফাংশন / ডেকরেটার শ্রেণিবদ্ধ ব্যবহার করা হয়। প্রথম যুক্তি উদাহরণের পরিবর্তে শ্রেণিতে উল্লেখ করা হবে

class ClassMethodDemo:
    @classmethod
    def foo(cls):
        print(f'cls is ClassMethodDemo: {cls is ClassMethodDemo}')

যেহেতু আমরা "শ্রেণিবদ্ধ" ব্যবহার করেছি আমরা নীচে কোনও উদাহরণ তৈরি না করেই পদ্ধতিটিকে "ফু" বলি

ClassMethodDemo.foo()

উপরে পদ্ধতির কলটি সত্য আসবে। যেহেতু প্রথম আর্গুমেন্ট ক্লাসটি আসলে "ClassMethodDemo" এর সাথে সম্পর্কিত

সারসংক্ষেপ:

  • শ্রেণিবদ্ধের প্রথম যুক্তি প্রাপ্ত যা "শ্রেণীর একটি রেফারেন্স (traditionতিহ্যগতভাবে ক্লস হিসাবে পরিচিত) নিজেই"
  • মেটা-ক্লাসের পদ্ধতিগুলি শ্রেণীবদ্ধ নয়। মেটা-ক্লাসের পদ্ধতিগুলি প্রথম যুক্তিটি গ্রহণ করে যা "উদাহরণের জন্য একটি রেফারেন্স (traditionতিহ্যগতভাবে স্ব হিসাবে স্বীকৃত) শ্রেণি নয়"
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.