चूंकि कक्षाएं मेटाक्लास के उदाहरण हैं, इसलिए यह अप्रत्याशित नहीं है कि मेटाक्लास पर एक "इंस्टेंस विधि" एक क्लासमेथोड की तरह व्यवहार करेगी।
हालांकि, हां, मतभेद हैं - और उनमें से कुछ शब्दार्थ से अधिक हैं:
- सबसे महत्वपूर्ण अंतर यह है कि मेटाक्लास में एक विधि एक वर्ग उदाहरण से "दृश्यमान" नहीं है । ऐसा इसलिए होता है क्योंकि पाइथन में विशेषता का पता लगाना (एक सरलीकृत तरीके से - वर्णनकर्ता पूर्ववर्ती समय ले सकते हैं) उदाहरण में एक विशेषता की खोज करते हैं - यदि यह उदाहरण में मौजूद नहीं है, तो पायथन उस इंस्टेंस की कक्षा में दिखता है, और फिर खोज जारी रहती है वर्ग के सुपरक्लास, लेकिन वर्ग के वर्ग पर नहीं । पायथन stdlib
abc.ABCMeta.registerविधि में इस सुविधा का उपयोग करते हैं। उस सुविधा का उपयोग अच्छे के लिए किया जा सकता है, क्योंकि वर्ग से संबंधित तरीके स्वयं को फिर से उपयोग करने के लिए स्वतंत्र हैं, उदाहरण के लिए बिना किसी संघर्ष के विशेषताएँ (लेकिन एक तरीका अभी भी संघर्ष होगा)।
- एक और अंतर, हालांकि स्पष्ट है, यह है कि मेटाक्लास में घोषित एक विधि कई वर्गों में उपलब्ध हो सकती है, अन्यथा संबंधित नहीं - यदि आपके पास अलग-अलग श्रेणी के पदानुक्रम हैं, तो वे जो भी व्यवहार करते हैं, उससे संबंधित नहीं हैं , लेकिन सभी वर्गों के लिए कुछ सामान्य कार्यक्षमता चाहते हैं। , आपको एक मिक्सिन वर्ग के साथ आना होगा, जिसे दोनों पदानुक्रमों में आधार के रूप में शामिल करना होगा (एक आवेदन रजिस्ट्री में सभी वर्गों को शामिल करने के लिए)। (एनबी। मिश्रण कभी-कभी मेटाक्लस की तुलना में बेहतर कॉल हो सकता है)
- क्लासमैथोड एक विशिष्ट "क्लासमेथोड" वस्तु है, जबकि मेटाक्लास में एक विधि एक साधारण कार्य है।
तो, ऐसा होता है कि क्लासमैथोड का उपयोग करने वाला तंत्र " डिस्क्रिप्टर प्रोटोकॉल " है। हालांकि सामान्य फ़ंक्शन में एक __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वस्तु नहीं है, अन्य अंतर, रनटाइम पर अस्पष्ट और व्यर्थ लगेंगे - लेकिन ऐसा इसलिए होता है क्योंकि भाषा को जाने की आवश्यकता नहीं होती है क्लासमैथोड्स के लिए विशेष नियमों के साथ अपने तरीके से बाहर: एक क्लासमेथोड घोषित करने के दोनों तरीके संभव हैं, परिणामस्वरूप भाषा डिजाइन - एक, इस तथ्य के लिए कि एक वर्ग स्वयं एक वस्तु है, और दूसरा, कई लोगों के बीच एक संभावना के रूप में, डिस्क्रिप्टर प्रोटोकॉल का उपयोग जो किसी को एक उदाहरण में और एक वर्ग में विशेषता का उपयोग करने की अनुमति देता है:
classmethodनिर्मित मूल कोड में परिभाषित किया गया है, लेकिन यह सिर्फ शुद्ध अजगर में कोडित किया जा सकता है और ठीक उसी तरह से काम करेगा। 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मेटाक्लास पर विशेष गुण विशेष वर्ग विशेषताओं के रूप में काम करेंगे, बस एक ही, कोई आश्चर्यजनक व्यवहार नहीं है।