पायथन में, मेटाक्लास क्या हैं और हम उनका उपयोग किस लिए करते हैं?

6532
e-satis 19 सितंबर 2008, 10:10

24 जवाब

सबसे बढ़िया उत्तर

एक मेटाक्लास एक वर्ग का वर्ग है। एक वर्ग परिभाषित करता है कि कक्षा का एक उदाहरण (यानी एक वस्तु) कैसे व्यवहार करता है जबकि एक मेटाक्लास परिभाषित करता है कि एक वर्ग कैसे व्यवहार करता है। एक वर्ग मेटाक्लास का एक उदाहरण है।

पाइथन में रहते हुए आप मेटाक्लास के लिए मनमानी कॉलेबल का उपयोग कर सकते हैं (जैसे Jerub दिखाता है), बेहतर तरीका यह है कि इसे वास्तविक वर्ग ही बनाया जाए। type पायथन में सामान्य मेटाक्लास है। type स्वयं एक वर्ग है, और यह स्वयं का प्रकार है। आप पूरी तरह से पायथन में type जैसा कुछ नहीं बना पाएंगे, लेकिन पायथन थोड़ा धोखा देता है। पायथन में अपना खुद का मेटाक्लास बनाने के लिए आप वास्तव में केवल type को उपवर्ग करना चाहते हैं।

एक मेटाक्लास का उपयोग आमतौर पर क्लास-फैक्ट्री के रूप में किया जाता है। जब आप क्लास को कॉल करके कोई ऑब्जेक्ट बनाते हैं, तो पायथन मेटाक्लास को कॉल करके एक नया क्लास (जब यह 'क्लास' स्टेटमेंट निष्पादित करता है) बनाता है। सामान्य __init__ और __new__ विधियों के साथ मिलकर, मेटाक्लास आपको कक्षा बनाते समय 'अतिरिक्त चीजें' करने की अनुमति देते हैं, जैसे कुछ रजिस्ट्री के साथ नई कक्षा को पंजीकृत करना या कक्षा को पूरी तरह से किसी और चीज़ से बदलना।

जब class स्टेटमेंट को निष्पादित किया जाता है, तो पायथन पहले class स्टेटमेंट के बॉडी को कोड के सामान्य ब्लॉक के रूप में निष्पादित करता है। परिणामी नेमस्पेस (एक ताना) कक्षा-से-बी के गुण रखता है। मेटाक्लास को क्लास-टू-बी (मेटाक्लास विरासत में मिला है) के बेसक्लास को देखकर निर्धारित किया जाता है, क्लास-टू-बी (यदि कोई हो) की __metaclass__ विशेषता या __metaclass__ वैश्विक चर . मेटाक्लास को तब नाम, आधार और वर्ग के गुणों के साथ बुलाया जाता है ताकि इसे तत्काल किया जा सके।

हालांकि, मेटाक्लास वास्तव में एक वर्ग के प्रकार को परिभाषित करते हैं, न कि केवल इसके लिए एक कारखाना, ताकि आप उनके साथ बहुत कुछ कर सकें। उदाहरण के लिए, आप मेटाक्लास पर सामान्य विधियों को परिभाषित कर सकते हैं। ये मेटाक्लास-विधियाँ क्लासमेथड्स की तरह हैं, जिसमें उन्हें बिना किसी उदाहरण के क्लास में बुलाया जा सकता है, लेकिन वे क्लासमेथड्स की तरह भी नहीं हैं, जिसमें उन्हें क्लास के इंस्टेंस पर नहीं कहा जा सकता है। type.__subclasses__() type मेटाक्लास पर एक विधि का एक उदाहरण है। आप कक्षा के व्यवहार को लागू करने या बदलने के लिए सामान्य 'जादू' विधियों, जैसे __add__, __iter__ और __getattr__ को भी परिभाषित कर सकते हैं।

यहाँ बिट्स और टुकड़ों का एक समग्र उदाहरण दिया गया है:

def make_hook(f):
    """Decorator to turn 'foo' method into '__foo__'"""
    f.is_hook = 1
    return f

class MyType(type):
    def __new__(mcls, name, bases, attrs):

        if name.startswith('None'):
            return None

        # Go over attributes and see if they should be renamed.
        newattrs = {}
        for attrname, attrvalue in attrs.iteritems():
            if getattr(attrvalue, 'is_hook', 0):
                newattrs['__%s__' % attrname] = attrvalue
            else:
                newattrs[attrname] = attrvalue

        return super(MyType, mcls).__new__(mcls, name, bases, newattrs)

    def __init__(self, name, bases, attrs):
        super(MyType, self).__init__(name, bases, attrs)

        # classregistry.register(self, self.interfaces)
        print "Would register class %s now." % self

    def __add__(self, other):
        class AutoClass(self, other):
            pass
        return AutoClass
        # Alternatively, to autogenerate the classname as well as the class:
        # return type(self.__name__ + other.__name__, (self, other), {})

    def unregister(self):
        # classregistry.unregister(self)
        print "Would unregister class %s now." % self

class MyObject:
    __metaclass__ = MyType


class NoneSample(MyObject):
    pass

# Will print "NoneType None"
print type(NoneSample), repr(NoneSample)

class Example(MyObject):
    def __init__(self, value):
        self.value = value
    @make_hook
    def add(self, other):
        return self.__class__(self.value + other.value)

# Will unregister the class
Example.unregister()

inst = Example(10)
# Will fail with an AttributeError
#inst.unregister()

print inst + inst
class Sibling(MyObject):
    pass

ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling (with no
# content of its own) although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__
3320
Cameron Savage 5 मार्च 2019, 00:34
17
class A(type):pass<NEWLINE>class B(type,metaclass=A):pass<NEWLINE>b.__class__ = b
 – 
pppery
3 अगस्त 2017, 17:34
30
पीपीपीरी का स्पष्ट रूप से मतलब था कि आप टाइप को मेटाक्लास के रूप में उपयोग किए बिना फिर से नहीं बना सकते हैं। जो कहना काफी उचित है।
 – 
Holle van
19 सितंबर 2018, 02:24
4
उदाहरण वर्ग के उदाहरण से अपंजीकृत () को नहीं बुलाया जाना चाहिए?
 – 
Ciasto piekarz
29 नवम्बर 2018, 03:59
17
ध्यान दें कि पायथन 3 में __metaclass__ समर्थित नहीं है। पायथन 3 में class MyObject(metaclass=MyType) का उपयोग करें, देखें python.org/dev/peps/pep-3115 और नीचे दिए गए उत्तर।
 – 
BlackShift
1 मई 2019, 11:36
3
दस्तावेज़ में बताया गया है कि मेटाक्लास कैसे चुना जाता है . मेटाक्लास को इतना विरासत में नहीं मिला है जितना इसे प्राप्त किया गया है। यदि आप एक मेटाक्लास निर्दिष्ट करते हैं, तो उसे प्रत्येक बेस क्लास मेटाक्लास का उपप्रकार होना चाहिए; अन्यथा, आप एक बेस क्लास मेटाक्लास का उपयोग करेंगे जो एक दूसरे बेस क्लास मेटाक्लास का उपप्रकार है। ध्यान दें कि यह संभव है कि नहीं मान्य मेटाक्लास मिल सके, और परिभाषा विफल हो जाएगी।
 – 
chepner
10 जिंदा 2020, 00:14

ध्यान दें, यह उत्तर Python 2.x के लिए है जैसा कि 2008 में लिखा गया था, मेटाक्लास 3.x में थोड़े अलग हैं।

मेटाक्लास गुप्त सॉस हैं जो 'क्लास' काम करते हैं। एक नई स्टाइल ऑब्जेक्ट के लिए डिफ़ॉल्ट मेटाक्लास को 'टाइप' कहा जाता है।

class type(object)
  |  type(object) -> the object's type
  |  type(name, bases, dict) -> a new type

मेटाक्लास 3 आर्ग लेते हैं। 'नाम', 'आधार' और 'तानाशाह'

यहीं से रहस्य शुरू होता है। इस उदाहरण वर्ग परिभाषा में देखें कि नाम, आधार और निर्देश कहां से आते हैं।

class ThisIsTheName(Bases, Are, Here):
    All_the_code_here
    def doesIs(create, a):
        dict

आइए एक मेटाक्लास परिभाषित करें जो प्रदर्शित करेगा कि 'वर्ग:' इसे कैसे कॉल करता है।

def test_metaclass(name, bases, dict):
    print 'The Class Name is', name
    print 'The Class Bases are', bases
    print 'The dict has', len(dict), 'elems, the keys are', dict.keys()

    return "yellow"

class TestName(object, None, int, 1):
    __metaclass__ = test_metaclass
    foo = 1
    def baz(self, arr):
        pass

print 'TestName = ', repr(TestName)

# output => 
The Class Name is TestName
The Class Bases are (<type 'object'>, None, <type 'int'>, 1)
The dict has 4 elems, the keys are ['baz', '__module__', 'foo', '__metaclass__']
TestName =  'yellow'

और अब, एक उदाहरण जिसका वास्तव में कुछ मतलब है, यह स्वचालित रूप से वर्ग पर सेट "विशेषताओं" सूची में चर बना देगा, और कोई नहीं पर सेट करेगा।

def init_attributes(name, bases, dict):
    if 'attributes' in dict:
        for attr in dict['attributes']:
            dict[attr] = None

    return type(name, bases, dict)

class Initialised(object):
    __metaclass__ = init_attributes
    attributes = ['foo', 'bar', 'baz']

print 'foo =>', Initialised.foo
# output=>
foo => None

ध्यान दें कि Initialised मेटाक्लास init_attributes होने से जो जादुई व्यवहार प्राप्त होता है, उसे Initialised के उपवर्ग में स्थानांतरित नहीं किया जाता है।

यहां एक और भी ठोस उदाहरण दिया गया है, जिसमें दिखाया गया है कि आप एक मेटाक्लास बनाने के लिए 'टाइप' को कैसे उपवर्गित कर सकते हैं जो क्लास बनाते समय एक क्रिया करता है। यह काफी पेचीदा है:

class MetaSingleton(type):
    instance = None
    def __call__(cls, *args, **kw):
        if cls.instance is None:
            cls.instance = super(MetaSingleton, cls).__call__(*args, **kw)
        return cls.instance

class Foo(object):
    __metaclass__ = MetaSingleton

a = Foo()
b = Foo()
assert a is b
449
ralh 6 नवम्बर 2019, 10:57

दूसरों ने समझाया है कि मेटाक्लास कैसे काम करते हैं और वे पायथन टाइप सिस्टम में कैसे फिट होते हैं। यहां एक उदाहरण दिया गया है कि उनका क्या उपयोग किया जा सकता है। एक परीक्षण ढांचे में मैंने लिखा था, मैं उस क्रम का ट्रैक रखना चाहता था जिसमें कक्षाओं को परिभाषित किया गया था, ताकि बाद में मैं उन्हें इस क्रम में तुरंत चालू कर सकूं। मुझे मेटाक्लास का उपयोग करके ऐसा करना सबसे आसान लगा।

class MyMeta(type):

    counter = 0

    def __init__(cls, name, bases, dic):
        type.__init__(cls, name, bases, dic)
        cls._order = MyMeta.counter
        MyMeta.counter += 1

class MyType(object):              # Python 2
    __metaclass__ = MyMeta

class MyType(metaclass=MyMeta):    # Python 3
    pass

जो कुछ भी MyType का उपवर्ग है, उसे एक वर्ग विशेषता _order मिलती है जो उस क्रम को रिकॉर्ड करती है जिसमें कक्षाओं को परिभाषित किया गया था।

201
kindall 28 नवम्बर 2016, 21:04
उदाहरण के लिए धन्यवाद। आपको MyBase से इनहेरिट करने की तुलना में यह आसान क्यों लगा, जिसका __init__(self) कहता है type(self)._order = MyBase.counter; MyBase.counter += 1 ?
 – 
Michael Gundlach
16 अप्रैल 2019, 20:59
4
मैं चाहता था कि कक्षाएं स्वयं हों, न कि उनके उदाहरण, गिने जाएं।
 – 
kindall
16 अप्रैल 2019, 21:09
सही, दुह। धन्यवाद। मेरा कोड प्रत्येक तात्कालिकता पर MyType की विशेषता को रीसेट कर देगा, और यदि MyType का उदाहरण कभी नहीं बनाया गया था तो वह कभी भी विशेषता सेट नहीं करेगा। उफ़। (और एक वर्ग संपत्ति भी काम कर सकती है, लेकिन मेटाक्लास के विपरीत यह काउंटर को स्टोर करने के लिए कोई स्पष्ट स्थान प्रदान नहीं करता है।)
 – 
Michael Gundlach
18 अप्रैल 2019, 00:58
1
यह एक मजेदार दिलचस्प उदाहरण है, कम से कम नहीं क्योंकि कोई वास्तव में देख सकता है कि एक विशिष्ट कठिनाई के समाधान की आपूर्ति के लिए मेटाक्लास को इसके साथ क्यों जोड़ा जा सकता है। ओटीओएच मैं इस बात से आश्वस्त होने के लिए संघर्ष करता हूं कि किसी को वास्तव में वस्तुओं को उस क्रम में तत्काल करने की आवश्यकता होगी जिसमें उनकी कक्षाएं परिभाषित की गई थीं: मुझे लगता है कि हमें इसके लिए आपका शब्द लेना होगा :)।
 – 
mike rodent
22 अक्टूबर 2019, 03:09
1
यह एक दस्तावेज परीक्षण ढांचा था और कक्षाएं परीक्षण की जाने वाली विशिष्ट फाइलों, चलाने के लिए परीक्षण, आदि के घोषणात्मक विवरण थीं। ढांचे ने उत्पाद, दस्तावेज़ और परीक्षण द्वारा समूहीकृत एक अच्छी तरह से स्वरूपित रिपोर्ट में इनके परिणामों की सूचना दी। रिपोर्ट अधिक उपयोगी थी यदि यह परीक्षण एक पूर्वानुमेय क्रम में चलाए गए थे। :-)
 – 
kindall
5 मई 2021, 23:57

मेटाक्लास के लिए एक उपयोग स्वचालित रूप से नए गुणों और विधियों को एक उदाहरण में जोड़ रहा है।

उदाहरण के लिए, यदि आप Django मॉडल देखते हैं, तो उनकी परिभाषा एक दिखती है थोड़ा भ्रमित। ऐसा लगता है कि आप केवल वर्ग गुणों को परिभाषित कर रहे हैं:

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

हालाँकि, रनटाइम पर व्यक्ति ऑब्जेक्ट सभी प्रकार के उपयोगी तरीकों से भरे होते हैं। कुछ अद्भुत मेटाक्लासरी के लिए स्रोत देखें।

183
Antti Rasinen 19 सितंबर 2008, 10:45
8
एक वर्ग में नए गुण और विधियों को जोड़ने वाली मेटा कक्षाओं का उपयोग नहीं है और एक उदाहरण नहीं है? जहां तक ​​​​मैं इसे समझता हूं, मेटा क्लास कक्षा को ही बदल देता है और नतीजतन बदले हुए वर्ग द्वारा उदाहरणों का निर्माण अलग-अलग किया जा सकता है। उन लोगों के लिए थोड़ा भ्रामक हो सकता है जो मेटा क्लास की प्रकृति प्राप्त करने का प्रयास करते हैं। उदाहरणों पर उपयोगी तरीके होने से सामान्य वंशानुक्रम द्वारा प्राप्त किया जा सकता है। उदाहरण के तौर पर Django कोड का संदर्भ अच्छा है, हालांकि।
 – 
trixn
28 जिंदा 2017, 02:24

मुझे लगता है कि मेटाक्लास प्रोग्रामिंग के लिए ओएनएलैम्प परिचय अच्छी तरह से लिखा गया है और पहले से ही कई साल पुराना होने के बावजूद इस विषय का वास्तव में अच्छा परिचय देता है।

http://www.onlamp.com/pub/a /python/2003/04/17/metaclasses.html (https://web.archive.org/web/20080206005253/http://www.onlamp.com/pub/a/python/ 2003/04/17/metaclasses.html)

संक्षेप में: एक वर्ग एक उदाहरण के निर्माण के लिए एक खाका है, एक वर्ग के निर्माण के लिए एक मेटाक्लास एक खाका है। यह आसानी से देखा जा सकता है कि इस व्यवहार को सक्षम करने के लिए पायथन कक्षाओं में प्रथम श्रेणी की वस्तुओं की भी आवश्यकता होती है।

मैंने खुद कभी नहीं लिखा है, लेकिन मुझे लगता है कि मेटाक्लास के सबसे अच्छे उपयोगों में से एक को Django Framework. मॉडल क्लास नए मॉडल या फॉर्म क्लास लिखने की घोषणात्मक शैली को सक्षम करने के लिए मेटाक्लास दृष्टिकोण का उपयोग करते हैं। जबकि मेटाक्लास कक्षा बना रहा है, सभी सदस्यों को कक्षा को स्वयं अनुकूलित करने की संभावना मिलती है।

कहने के लिए बाकी है: यदि आप नहीं जानते कि मेटाक्लास क्या हैं, तो संभावना है कि आपको उनकी आवश्यकता नहीं होगी 99% है।

145
Yet Another User 13 अगस्त 2018, 07:53

मेटाक्लास क्या हैं? आप इन्हें किसके लिए इस्तेमाल करते हैं?

TLDR: एक मेटाक्लास एक वर्ग के लिए व्यवहार को तत्काल और परिभाषित करता है जैसे एक वर्ग तत्काल करता है और एक उदाहरण के लिए व्यवहार को परिभाषित करता है।

छद्म कोड:

>>> Class(...)
instance

उपरोक्त परिचित दिखना चाहिए। अच्छा, Class कहाँ से आता है? यह एक मेटाक्लास (भी छद्म कोड) का एक उदाहरण है:

>>> Metaclass(...)
Class

वास्तविक कोड में, हम डिफ़ॉल्ट मेटाक्लास, type पास कर सकते हैं, वह सब कुछ जो हमें एक क्लास को इंस्टेंट करने के लिए चाहिए और हमें एक क्लास मिलती है:

>>> type('Foo', (object,), {}) # requires a name, bases, and a namespace
<class '__main__.Foo'>

इसे अलग तरह से रखना

  • एक वर्ग एक उदाहरण के लिए है जैसे मेटाक्लास एक वर्ग के लिए है।

    जब हम किसी वस्तु को इंस्टेंट करते हैं, तो हमें एक उदाहरण मिलता है:

    >>> object()                          # instantiation of class
    <object object at 0x7f9069b4e0b0>     # instance
    

    इसी तरह, जब हम डिफ़ॉल्ट मेटाक्लास, type के साथ स्पष्ट रूप से एक वर्ग को परिभाषित करते हैं, तो हम इसे तत्काल करते हैं:

    >>> type('Object', (object,), {})     # instantiation of metaclass
    <class '__main__.Object'>             # instance
    
  • एक और तरीका रखो, एक वर्ग मेटाक्लास का एक उदाहरण है:

    >>> isinstance(object, type)
    True
    
  • तीसरा तरीका रखो, एक मेटाक्लास एक वर्ग का वर्ग है।

    >>> type(object) == type
    True
    >>> object.__class__
    <class 'type'>
    

जब आप एक क्लास डेफिनिशन लिखते हैं और पायथन इसे निष्पादित करता है, तो यह क्लास ऑब्जेक्ट को इंस्टेंट करने के लिए एक मेटाक्लास का उपयोग करता है (जो बदले में, उस क्लास के इंस्टेंस को इंस्टेंट करने के लिए उपयोग किया जाएगा)।

जिस तरह हम कस्टम ऑब्जेक्ट इंस्टेंस के व्यवहार को बदलने के लिए क्लास डेफिनिशन का उपयोग कर सकते हैं, उसी तरह हम क्लास ऑब्जेक्ट के व्यवहार के तरीके को बदलने के लिए मेटाक्लास क्लास डेफिनिशन का उपयोग कर सकते हैं।

उनका उपयोग किस लिए किया जा सकता है? दस्तावेज़ से:

मेटाक्लास के लिए संभावित उपयोग असीमित हैं। खोजे गए कुछ विचारों में लॉगिंग, इंटरफ़ेस जांच, स्वचालित प्रतिनिधिमंडल, स्वचालित संपत्ति निर्माण, प्रॉक्सी, ढांचे, और स्वचालित संसाधन लॉकिंग/सिंक्रनाइज़ेशन शामिल हैं।

फिर भी, आमतौर पर उपयोगकर्ताओं को मेटाक्लास का उपयोग करने से बचने के लिए प्रोत्साहित किया जाता है जब तक कि बिल्कुल आवश्यक न हो।

हर बार जब आप कक्षा बनाते हैं तो आप मेटाक्लास का उपयोग करते हैं:

जब आप एक वर्ग परिभाषा लिखते हैं, उदाहरण के लिए, इस तरह,

class Foo(object): 
    'demo'

आप क्लास ऑब्जेक्ट को तुरंत चालू करते हैं।

>>> Foo
<class '__main__.Foo'>
>>> isinstance(Foo, type), isinstance(Foo, object)
(True, True)

यह उपयुक्त तर्कों के साथ type को कार्यात्मक रूप से कॉल करने और उस नाम के एक चर को परिणाम निर्दिष्ट करने जैसा ही है:

name = 'Foo'
bases = (object,)
namespace = {'__doc__': 'demo'}
Foo = type(name, bases, namespace)

ध्यान दें, कुछ चीज़ें अपने आप __dict__ में जुड़ जाती हैं, यानी नाम स्थान:

>>> Foo.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, 
'__module__': '__main__', '__weakref__': <attribute '__weakref__' 
of 'Foo' objects>, '__doc__': 'demo'})

हमारे द्वारा बनाई गई वस्तु का मेटाक्लास, दोनों ही मामलों में, type है।

(कक्षा की सामग्री पर एक साइड-नोट __dict__: __module__ है क्योंकि कक्षाओं को पता होना चाहिए कि उन्हें कहां परिभाषित किया गया है, और __dict__ और __weakref__ हैं क्योंकि हम __slots__ को परिभाषित न करें - यदि हम परिभाषित करते हैं __slots__ तो हम इसमें थोड़ी सी जगह बचा लेंगे उदाहरण, जैसा कि हम __dict__ और __weakref__ को बहिष्कृत करके अस्वीकार कर सकते हैं। उदाहरण के लिए:

>>> Baz = type('Bar', (object,), {'__doc__': 'demo', '__slots__': ()})
>>> Baz.__dict__
mappingproxy({'__doc__': 'demo', '__slots__': (), '__module__': '__main__'})

... लेकिन मैं पीछे हटा।)

हम किसी भी अन्य वर्ग परिभाषा की तरह ही type का विस्तार कर सकते हैं:

यहां कक्षाओं का डिफ़ॉल्ट __repr__ है:

>>> Foo
<class '__main__.Foo'>

सबसे मूल्यवान चीजों में से एक जो हम डिफ़ॉल्ट रूप से पायथन ऑब्जेक्ट लिखने में कर सकते हैं, वह है इसे एक अच्छा __repr__ प्रदान करना। जब हम help(repr) को कॉल करते हैं, तो हमें पता चलता है कि __repr__ के लिए एक अच्छी परीक्षा है, जिसमें समानता के लिए एक परीक्षण की भी आवश्यकता होती है - obj == eval(repr(obj))। हमारे प्रकार के वर्ग के उदाहरणों के लिए __repr__ और __eq__ का निम्नलिखित सरल कार्यान्वयन हमें एक प्रदर्शन प्रदान करता है जो डिफ़ॉल्ट __repr__ कक्षाओं में सुधार कर सकता है:

class Type(type):
    def __repr__(cls):
        """
        >>> Baz
        Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
        >>> eval(repr(Baz))
        Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
        """
        metaname = type(cls).__name__
        name = cls.__name__
        parents = ', '.join(b.__name__ for b in cls.__bases__)
        if parents:
            parents += ','
        namespace = ', '.join(': '.join(
          (repr(k), repr(v) if not isinstance(v, type) else v.__name__))
               for k, v in cls.__dict__.items())
        return '{0}(\'{1}\', ({2}), {{{3}}})'.format(metaname, name, parents, namespace)
    def __eq__(cls, other):
        """
        >>> Baz == eval(repr(Baz))
        True            
        """
        return (cls.__name__, cls.__bases__, cls.__dict__) == (
                other.__name__, other.__bases__, other.__dict__)

इसलिए अब जब हम इस मेटाक्लास के साथ एक ऑब्जेक्ट बनाते हैं, तो कमांड लाइन पर प्रतिध्वनित __repr__ डिफ़ॉल्ट की तुलना में बहुत कम बदसूरत दृश्य प्रदान करता है:

>>> class Bar(object): pass
>>> Baz = Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
>>> Baz
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})

क्लास इंस्टेंस के लिए परिभाषित एक अच्छे __repr__ के साथ, हमारे पास अपने कोड को डीबग करने की एक मजबूत क्षमता है। हालांकि, eval(repr(Class)) के साथ और अधिक जांच की संभावना नहीं है (क्योंकि कार्यों को उनके डिफ़ॉल्ट __repr__'s से निकालना असंभव होगा)।

एक अपेक्षित उपयोग: __prepare__ एक नाम स्थान

यदि, उदाहरण के लिए, हम यह जानना चाहते हैं कि किस क्रम में एक वर्ग के तरीके बनाए गए हैं, तो हम कक्षा के नाम स्थान के रूप में एक आदेशित निर्देश प्रदान कर सकते हैं। हम इसे __prepare__ के साथ करेंगे जो वर्ग के लिए नेमस्पेस तानाशाही अगर इसे पायथन 3 में लागू किया गया है:

from collections import OrderedDict

class OrderedType(Type):
    @classmethod
    def __prepare__(metacls, name, bases, **kwargs):
        return OrderedDict()
    def __new__(cls, name, bases, namespace, **kwargs):
        result = Type.__new__(cls, name, bases, dict(namespace))
        result.members = tuple(namespace)
        return result

और उपयोग:

class OrderedMethodsObject(object, metaclass=OrderedType):
    def method1(self): pass
    def method2(self): pass
    def method3(self): pass
    def method4(self): pass

और अब हमारे पास उस क्रम का रिकॉर्ड है जिसमें ये तरीके (और अन्य वर्ग विशेषताएँ) बनाए गए थे:

>>> OrderedMethodsObject.members
('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4')

ध्यान दें, यह उदाहरण दस्तावेज़ीकरण से अनुकूलित किया गया था - नया < a href="https://github.com/python/cpython/blob/master/Lib/enum.py" rel="noreferrer">मानक पुस्तकालय में एनम ऐसा करता है।

तो हमने जो किया वह एक वर्ग बनाकर मेटाक्लास को तुरंत चालू कर दिया। हम मेटाक्लास के साथ भी वैसा ही व्यवहार कर सकते हैं जैसा हम किसी अन्य वर्ग के साथ करते हैं। इसमें एक विधि समाधान आदेश है:

>>> inspect.getmro(OrderedType)
(<class '__main__.OrderedType'>, <class '__main__.Type'>, <class 'type'>, <class 'object'>)

और इसमें लगभग सही repr है (जिसे हम तब तक नहीं निकाल सकते जब तक कि हमें अपने कार्यों का प्रतिनिधित्व करने का कोई तरीका नहीं मिल जाता।)

>>> OrderedMethodsObject
OrderedType('OrderedMethodsObject', (object,), {'method1': <function OrderedMethodsObject.method1 at 0x0000000002DB01E0>, 'members': ('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4'), 'method3': <function OrderedMet
hodsObject.method3 at 0x0000000002DB02F0>, 'method2': <function OrderedMethodsObject.method2 at 0x0000000002DB0268>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'OrderedMethodsObject' objects>, '__doc__': None, '__d
ict__': <attribute '__dict__' of 'OrderedMethodsObject' objects>, 'method4': <function OrderedMethodsObject.method4 at 0x0000000002DB0378>})
132
Aaron Hall 30 अगस्त 2017, 06:19

पायथन 3 अपडेट

मेटाक्लास में (इस बिंदु पर) दो प्रमुख विधियाँ हैं:

  • __prepare__, और
  • __new__

__prepare__ आपको एक कस्टम मैपिंग (जैसे OrderedDict) की आपूर्ति करने देता है, जिसे क्लास बनाते समय नेमस्पेस के रूप में इस्तेमाल किया जा सकता है। आप जो भी नामस्थान चुनते हैं उसका एक उदाहरण आपको वापस करना होगा। यदि आप __prepare__ लागू नहीं करते हैं तो एक सामान्य dict का उपयोग किया जाता है।

__new__ अंतिम वर्ग के वास्तविक निर्माण/संशोधन के लिए जिम्मेदार है।

एक नंगे-हड्डियाँ, कुछ न करें-अतिरिक्त मेटाक्लास चाहेंगे:

class Meta(type):

    def __prepare__(metaclass, cls, bases):
        return dict()

    def __new__(metacls, cls, bases, clsdict):
        return super().__new__(metacls, cls, bases, clsdict)

एक साधारण उदाहरण:

मान लें कि आप अपनी विशेषताओं पर कुछ सरल सत्यापन कोड चलाना चाहते हैं -- जैसे यह हमेशा एक int या एक str होना चाहिए। मेटाक्लास के बिना, आपकी कक्षा कुछ इस तरह दिखेगी:

class Person:
    weight = ValidateType('weight', int)
    age = ValidateType('age', int)
    name = ValidateType('name', str)

जैसा कि आप देख सकते हैं, आपको विशेषता का नाम दो बार दोहराना होगा। यह परेशान करने वाले बग के साथ-साथ टाइपो को संभव बनाता है।

एक साधारण मेटाक्लास उस समस्या का समाधान कर सकता है:

class Person(metaclass=Validator):
    weight = ValidateType(int)
    age = ValidateType(int)
    name = ValidateType(str)

मेटाक्लास इस तरह दिखेगा (__prepare__ का उपयोग नहीं कर रहा है क्योंकि इसकी आवश्यकता नहीं है):

class Validator(type):
    def __new__(metacls, cls, bases, clsdict):
        # search clsdict looking for ValidateType descriptors
        for name, attr in clsdict.items():
            if isinstance(attr, ValidateType):
                attr.name = name
                attr.attr = '_' + name
        # create final class and return it
        return super().__new__(metacls, cls, bases, clsdict)

का एक नमूना रन:

p = Person()
p.weight = 9
print(p.weight)
p.weight = '9'

उत्पादन करता है:

9
Traceback (most recent call last):
  File "simple_meta.py", line 36, in <module>
    p.weight = '9'
  File "simple_meta.py", line 24, in __set__
    (self.name, self.type, value))
TypeError: weight must be of type(s) <class 'int'> (got '9')

नोट: यह उदाहरण इतना आसान है कि इसे क्लास डेकोरेटर के साथ भी पूरा किया जा सकता था, लेकिन संभवतः एक वास्तविक मेटाक्लास बहुत कुछ कर रहा होगा।

संदर्भ के लिए 'ValidateType' वर्ग:

class ValidateType:
    def __init__(self, type):
        self.name = None  # will be set by metaclass
        self.attr = None  # will be set by metaclass
        self.type = type
    def __get__(self, inst, cls):
        if inst is None:
            return self
        else:
            return inst.__dict__[self.attr]
    def __set__(self, inst, value):
        if not isinstance(value, self.type):
            raise TypeError('%s must be of type(s) %s (got %r)' %
                    (self.name, self.type, value))
        else:
            inst.__dict__[self.attr] = value
99
Ethan Furman 1 मार्च 2016, 22:48
1
ध्यान दें कि अजगर 3.6 के बाद से, आप डिस्क्रिप्टर में नाम सेट करने के लिए डिस्क्रिप्टर (ValidateType) में __set_name__(cls, name) का उपयोग कर सकते हैं (self.name और इस मामले में भी self.attr)। इसे इस विशिष्ट सामान्य उपयोग के मामले के लिए मेटाक्लास में गोता लगाने के लिए नहीं जोड़ा गया था (देखें पीईपी 487)।
 – 
Lars
3 मार्च 2020, 12:56

एक मेटाक्लास एक वर्ग है जो बताता है कि कैसे (कुछ) अन्य वर्ग बनाया जाना चाहिए।

यह एक ऐसा मामला है जहां मैंने अपनी समस्या के समाधान के रूप में मेटाक्लास को देखा: मुझे वास्तव में एक जटिल समस्या थी, जिसे शायद अलग तरीके से हल किया जा सकता था, लेकिन मैंने इसे मेटाक्लास का उपयोग करके हल करना चुना। जटिलता के कारण, यह मेरे द्वारा लिखे गए कुछ मॉड्यूल में से एक है जहां मॉड्यूल में टिप्पणियां लिखे गए कोड की मात्रा को पार करती हैं। यह रहा...

#!/usr/bin/env python

# Copyright (C) 2013-2014 Craig Phillips.  All rights reserved.

# This requires some explaining.  The point of this metaclass excercise is to
# create a static abstract class that is in one way or another, dormant until
# queried.  I experimented with creating a singlton on import, but that did
# not quite behave how I wanted it to.  See now here, we are creating a class
# called GsyncOptions, that on import, will do nothing except state that its
# class creator is GsyncOptionsType.  This means, docopt doesn't parse any
# of the help document, nor does it start processing command line options.
# So importing this module becomes really efficient.  The complicated bit
# comes from requiring the GsyncOptions class to be static.  By that, I mean
# any property on it, may or may not exist, since they are not statically
# defined; so I can't simply just define the class with a whole bunch of
# properties that are @property @staticmethods.
#
# So here's how it works:
#
# Executing 'from libgsync.options import GsyncOptions' does nothing more
# than load up this module, define the Type and the Class and import them
# into the callers namespace.  Simple.
#
# Invoking 'GsyncOptions.debug' for the first time, or any other property
# causes the __metaclass__ __getattr__ method to be called, since the class
# is not instantiated as a class instance yet.  The __getattr__ method on
# the type then initialises the class (GsyncOptions) via the __initialiseClass
# method.  This is the first and only time the class will actually have its
# dictionary statically populated.  The docopt module is invoked to parse the
# usage document and generate command line options from it.  These are then
# paired with their defaults and what's in sys.argv.  After all that, we
# setup some dynamic properties that could not be defined by their name in
# the usage, before everything is then transplanted onto the actual class
# object (or static class GsyncOptions).
#
# Another piece of magic, is to allow command line options to be set in
# in their native form and be translated into argparse style properties.
#
# Finally, the GsyncListOptions class is actually where the options are
# stored.  This only acts as a mechanism for storing options as lists, to
# allow aggregation of duplicate options or options that can be specified
# multiple times.  The __getattr__ call hides this by default, returning the
# last item in a property's list.  However, if the entire list is required,
# calling the 'list()' method on the GsyncOptions class, returns a reference
# to the GsyncListOptions class, which contains all of the same properties
# but as lists and without the duplication of having them as both lists and
# static singlton values.
#
# So this actually means that GsyncOptions is actually a static proxy class...
#
# ...And all this is neatly hidden within a closure for safe keeping.
def GetGsyncOptionsType():
    class GsyncListOptions(object):
        __initialised = False

    class GsyncOptionsType(type):
        def __initialiseClass(cls):
            if GsyncListOptions._GsyncListOptions__initialised: return

            from docopt import docopt
            from libgsync.options import doc
            from libgsync import __version__

            options = docopt(
                doc.__doc__ % __version__,
                version = __version__,
                options_first = True
            )

            paths = options.pop('<path>', None)
            setattr(cls, "destination_path", paths.pop() if paths else None)
            setattr(cls, "source_paths", paths)
            setattr(cls, "options", options)

            for k, v in options.iteritems():
                setattr(cls, k, v)

            GsyncListOptions._GsyncListOptions__initialised = True

        def list(cls):
            return GsyncListOptions

        def __getattr__(cls, name):
            cls.__initialiseClass()
            return getattr(GsyncListOptions, name)[-1]

        def __setattr__(cls, name, value):
            # Substitut option names: --an-option-name for an_option_name
            import re
            name = re.sub(r'^__', "", re.sub(r'-', "_", name))
            listvalue = []

            # Ensure value is converted to a list type for GsyncListOptions
            if isinstance(value, list):
                if value:
                    listvalue = [] + value
                else:
                    listvalue = [ None ]
            else:
                listvalue = [ value ]

            type.__setattr__(GsyncListOptions, name, listvalue)

    # Cleanup this module to prevent tinkering.
    import sys
    module = sys.modules[__name__]
    del module.__dict__['GetGsyncOptionsType']

    return GsyncOptionsType

# Our singlton abstract proxy class.
class GsyncOptions(object):
    __metaclass__ = GetGsyncOptionsType()
68
3 revs, 2 users 99% 25 जिंदा 2016, 23:08

type वास्तव में एक metaclass है -- एक वर्ग जो अन्य वर्ग बनाता है। अधिकांश metaclass, type के उपवर्ग हैं। metaclass अपने पहले तर्क के रूप में new वर्ग प्राप्त करता है और नीचे बताए गए विवरण के साथ वर्ग वस्तु तक पहुंच प्रदान करता है:

>>> class MetaClass(type):
...     def __init__(cls, name, bases, attrs):
...         print ('class name: %s' %name )
...         print ('Defining class %s' %cls)
...         print('Bases %s: ' %bases)
...         print('Attributes')
...         for (name, value) in attrs.items():
...             print ('%s :%r' %(name, value))
... 

>>> class NewClass(object, metaclass=MetaClass):
...    get_choch='dairy'
... 
class name: NewClass
Bases <class 'object'>: 
Defining class <class 'NewClass'>
get_choch :'dairy'
__module__ :'builtins'
__qualname__ :'NewClass'

Note:

ध्यान दें कि कक्षा को किसी भी समय तत्काल नहीं किया गया था; वर्ग बनाने का सरल कार्य metaclass के निष्पादन को ट्रिगर करता है।

53
Chankey Pathak 29 अगस्त 2017, 08:23

टीएल; डॉ संस्करण

type(obj) फ़ंक्शन आपको किसी ऑब्जेक्ट का प्रकार बताता है।

किसी वर्ग का type() उसका मेटाक्लास होता है।

मेटाक्लास का उपयोग करने के लिए:

class Foo(object):
    __metaclass__ = MyMetaClass

type इसका अपना मेटाक्लास है। एक वर्ग का वर्ग एक मेटाक्लास है- एक वर्ग का शरीर मेटाक्लास को दिया गया तर्क है जिसका उपयोग कक्षा के निर्माण के लिए किया जाता है।

यहां आप वर्ग निर्माण को अनुकूलित करने के लिए मेटाक्लास का उपयोग करने के तरीके के बारे में पढ़ सकते हैं।

55
noɥʇʎԀʎzɐɹƆ 5 पद 2019, 19:27

पायथन वर्ग स्वयं वस्तुएं हैं - उदाहरण के लिए - उनके मेटा-क्लास के।

डिफ़ॉल्ट मेटाक्लास, जो तब लागू होता है जब आप कक्षाओं को इस प्रकार निर्धारित करते हैं:

class foo:
    ...

मेटा क्लास का उपयोग कुछ नियमों को कक्षाओं के पूरे सेट पर लागू करने के लिए किया जाता है। उदाहरण के लिए, मान लें कि आप डेटाबेस तक पहुंचने के लिए एक ओआरएम बना रहे हैं, और आप चाहते हैं कि प्रत्येक तालिका से रिकॉर्ड उस तालिका में मैप किए गए वर्ग के हों (फ़ील्ड, व्यावसायिक नियमों आदि के आधार पर), मेटाक्लास का संभावित उपयोग उदाहरण के लिए, कनेक्शन पूल तर्क है, जो सभी तालिकाओं से रिकॉर्ड के सभी वर्गों द्वारा साझा किया जाता है। एक अन्य उपयोग विदेशी कुंजियों का समर्थन करने के लिए तर्क है, जिसमें रिकॉर्ड के कई वर्ग शामिल हैं।

जब आप मेटाक्लास को परिभाषित करते हैं, तो आप उप-वर्ग टाइप करते हैं, और अपने तर्क को सम्मिलित करने के लिए निम्नलिखित जादू विधियों को ओवरराइड कर सकते हैं।

class somemeta(type):
    __new__(mcs, name, bases, clsdict):
      """
  mcs: is the base metaclass, in this case type.
  name: name of the new class, as provided by the user.
  bases: tuple of base classes 
  clsdict: a dictionary containing all methods and attributes defined on class

  you must return a class object by invoking the __new__ constructor on the base metaclass. 
 ie: 
    return type.__call__(mcs, name, bases, clsdict).

  in the following case:

  class foo(baseclass):
        __metaclass__ = somemeta

  an_attr = 12

  def bar(self):
      ...

  @classmethod
  def foo(cls):
      ...

      arguments would be : ( somemeta, "foo", (baseclass, baseofbase,..., object), {"an_attr":12, "bar": <function>, "foo": <bound class method>}

      you can modify any of these values before passing on to type
      """
      return type.__call__(mcs, name, bases, clsdict)


    def __init__(self, name, bases, clsdict):
      """ 
      called after type has been created. unlike in standard classes, __init__ method cannot modify the instance (cls) - and should be used for class validaton.
      """
      pass


    def __prepare__():
        """
        returns a dict or something that can be used as a namespace.
        the type will then attach methods and attributes from class definition to it.

        call order :

        somemeta.__new__ ->  type.__new__ -> type.__init__ -> somemeta.__init__ 
        """
        return dict()

    def mymethod(cls):
        """ works like a classmethod, but for class objects. Also, my method will not be visible to instances of cls.
        """
        pass

वैसे भी, वे दो सबसे अधिक इस्तेमाल किए जाने वाले हुक हैं। मेटाक्लासिंग शक्तिशाली है, और ऊपर कहीं नहीं है और मेटाक्लासिंग के लिए उपयोग की विस्तृत सूची है।

36
Xingzhou Liu 13 जुलाई 2017, 11:18

प्रकार () फ़ंक्शन किसी ऑब्जेक्ट के प्रकार को वापस कर सकता है या एक नया प्रकार बना सकता है,

उदाहरण के लिए, हम टाइप () फ़ंक्शन के साथ एक हाय क्लास बना सकते हैं और क्लास हाय (ऑब्जेक्ट) के साथ इस तरह से उपयोग करने की आवश्यकता नहीं है:

def func(self, name='mike'):
    print('Hi, %s.' % name)

Hi = type('Hi', (object,), dict(hi=func))
h = Hi()
h.hi()
Hi, mike.

type(Hi)
type

type(h)
__main__.Hi

कक्षाओं को गतिशील रूप से बनाने के लिए प्रकार () का उपयोग करने के अलावा, आप वर्ग के निर्माण व्यवहार को नियंत्रित कर सकते हैं और मेटाक्लास का उपयोग कर सकते हैं।

पायथन ऑब्जेक्ट मॉडल के अनुसार, वर्ग वस्तु है, इसलिए वर्ग को किसी अन्य निश्चित वर्ग का उदाहरण होना चाहिए। डिफ़ॉल्ट रूप से, एक पायथन वर्ग प्रकार वर्ग का उदाहरण है। यही है, प्रकार अधिकांश अंतर्निहित कक्षाओं का मेटाक्लास और उपयोगकर्ता-परिभाषित वर्गों का मेटाक्लास है।

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class CustomList(list, metaclass=ListMetaclass):
    pass

lst = CustomList()
lst.add('custom_list_1')
lst.add('custom_list_2')

lst
['custom_list_1', 'custom_list_2']

जब हम मेटाक्लास में कीवर्ड तर्क पारित करते हैं तो जादू प्रभावी होगा, यह लिस्टमेटाक्लास के माध्यम से कस्टमलिस्ट बनाने के लिए पायथन दुभाषिया को इंगित करता है। नया (), इस बिंदु पर, हम वर्ग परिभाषा को संशोधित कर सकते हैं, उदाहरण के लिए, और एक नई विधि जोड़ सकते हैं और फिर संशोधित परिभाषा वापस कर सकते हैं।

30
binbjz 12 जिंदा 2018, 12:30

प्रकाशित उत्तरों के अलावा मैं कह सकता हूं कि एक metaclass एक वर्ग के व्यवहार को परिभाषित करता है। तो, आप स्पष्ट रूप से अपना मेटाक्लास सेट कर सकते हैं। जब भी Python को कोई कीवर्ड class मिलता है तो वह metaclass को खोजना शुरू कर देता है। यदि यह नहीं मिला है - डिफ़ॉल्ट मेटाक्लास प्रकार का उपयोग क्लास के ऑब्जेक्ट को बनाने के लिए किया जाता है। __metaclass__ विशेषता का उपयोग करके, आप अपनी कक्षा का metaclass सेट कर सकते हैं:

class MyClass:
   __metaclass__ = type
   # write here other method
   # write here one more method

print(MyClass.__metaclass__)

यह इस तरह के आउटपुट का उत्पादन करेगा:

class 'type'

और, ज़ाहिर है, आप अपनी कक्षा का उपयोग करके बनाए गए किसी भी वर्ग के व्यवहार को परिभाषित करने के लिए अपना खुद का metaclass बना सकते हैं।

ऐसा करने के लिए, आपका डिफ़ॉल्ट metaclass प्रकार वर्ग इनहेरिट किया जाना चाहिए क्योंकि यह मुख्य metaclass है:

class MyMetaClass(type):
   __metaclass__ = type
   # you can write here any behaviour you want

class MyTestClass:
   __metaclass__ = MyMetaClass

Obj = MyTestClass()
print(Obj.__metaclass__)
print(MyMetaClass.__metaclass__)

आउटपुट होगा:

class '__main__.MyMetaClass'
class 'type'
21
Andy Jazz 15 सितंबर 2018, 16:17

ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में, मेटाक्लास एक ऐसा वर्ग है जिसके उदाहरण वर्ग हैं। जिस तरह एक सामान्य वर्ग कुछ वस्तुओं के व्यवहार को परिभाषित करता है, एक मेटाक्लास निश्चित वर्ग के व्यवहार और उनके उदाहरणों को परिभाषित करता है। दूसरे शब्दों में, यह एक वर्ग का वर्ग है। मेटाक्लास का उपयोग वर्ग बनाने के लिए किया जाता है, जैसे कि वस्तु एक वर्ग का उदाहरण है, एक वर्ग एक मेटाक्लास का एक उदाहरण है। पायथन कक्षाओं में वस्तुओं को भी माना जाता है।

9
Venu Gopal Tewari 9 जुलाई 2019, 08:45
2
किताबी परिभाषा देने के बजाय कुछ उदाहरण जोड़ देते तो अच्छा होता। ऐसा लगता है कि आपके उत्तर की पहली पंक्ति मेटाक्लासेस की विकिपीडिया प्रविष्टि से कॉपी की गई है।
 – 
verisimilitude
13 जुलाई 2019, 20:41
1
मैं यह भी सीख रहा हूं कि क्या आप अपने अनुभव से कुछ व्यावहारिक उदाहरण प्रदान करके इस उत्तर को बेहतर बनाने में मेरी मदद कर सकते हैं ??
 – 
Venu Gopal Tewari
15 जुलाई 2019, 09:02

यहां इसका एक और उदाहरण दिया गया है कि इसका उपयोग किस लिए किया जा सकता है:

  • आप metaclass का उपयोग इसके इंस्टेंस (कक्षा) के कार्य को बदलने के लिए कर सकते हैं।
class MetaMemberControl(type):
    __slots__ = ()

    @classmethod
    def __prepare__(mcs, f_cls_name, f_cls_parents,  # f_cls means: future class
                    meta_args=None, meta_options=None):  # meta_args and meta_options is not necessarily needed, just so you know.
        f_cls_attr = dict()
        if not "do something or if you want to define your cool stuff of dict...":
            return dict(make_your_special_dict=None)
        else:
            return f_cls_attr

    def __new__(mcs, f_cls_name, f_cls_parents, f_cls_attr,
                meta_args=None, meta_options=None):

        original_getattr = f_cls_attr.get('__getattribute__')
        original_setattr = f_cls_attr.get('__setattr__')

        def init_getattr(self, item):
            if not item.startswith('_'):  # you can set break points at here
                alias_name = '_' + item
                if alias_name in f_cls_attr['__slots__']:
                    item = alias_name
            if original_getattr is not None:
                return original_getattr(self, item)
            else:
                return super(eval(f_cls_name), self).__getattribute__(item)

        def init_setattr(self, key, value):
            if not key.startswith('_') and ('_' + key) in f_cls_attr['__slots__']:
                raise AttributeError(f"you can't modify private members:_{key}")
            if original_setattr is not None:
                original_setattr(self, key, value)
            else:
                super(eval(f_cls_name), self).__setattr__(key, value)

        f_cls_attr['__getattribute__'] = init_getattr
        f_cls_attr['__setattr__'] = init_setattr

        cls = super().__new__(mcs, f_cls_name, f_cls_parents, f_cls_attr)
        return cls


class Human(metaclass=MetaMemberControl):
    __slots__ = ('_age', '_name')

    def __init__(self, name, age):
        self._name = name
        self._age = age

    def __getattribute__(self, item):
        """
        is just for IDE recognize.
        """
        return super().__getattribute__(item)

    """ with MetaMemberControl then you don't have to write as following
    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age
    """


def test_demo():
    human = Human('Carson', 27)
    # human.age = 18  # you can't modify private members:_age  <-- this is defined by yourself.
    # human.k = 18  # 'Human' object has no attribute 'k'  <-- system error.
    age1 = human._age  # It's OK, although the IDE will show some warnings. (Access to a protected member _age of a class)

    age2 = human.age  # It's OK! see below:
    """
    if you do not define `__getattribute__` at the class of Human,
    the IDE will show you: Unresolved attribute reference 'age' for class 'Human'
    but it's ok on running since the MetaMemberControl will help you.
    """


if __name__ == '__main__':
    test_demo()

metaclass शक्तिशाली है, आप इसके साथ बहुत सी चीजें (जैसे बंदर जादू) कर सकते हैं, लेकिन सावधान रहें यह केवल आपको ही पता चल सकता है।

10
Carson 20 पद 2019, 14:03

पायथन में एक वर्ग एक वस्तु है, और किसी भी अन्य वस्तु की तरह, यह "कुछ" का एक उदाहरण है। यह "कुछ" जिसे मेटाक्लास कहा जाता है। यह मेटाक्लास एक विशेष प्रकार का वर्ग है जो अन्य वर्ग की वस्तुओं को बनाता है। इसलिए, नए वर्ग बनाने के लिए मेटाक्लास जिम्मेदार है। यह प्रोग्रामर को कक्षाएं उत्पन्न करने के तरीके को अनुकूलित करने की अनुमति देता है।

मेटाक्लास बनाने के लिए, आमतौर पर नई() और init() विधियों को ओवरराइड किया जाता है। ऑब्जेक्ट बनाने के तरीके को बदलने के लिए नया() ओवरराइड किया जा सकता है, जबकि init() ऑब्जेक्ट को इनिशियलाइज़ करने के तरीके को बदलने के लिए ओवरराइड किया जा सकता है। मेटाक्लास कई तरीकों से बनाया जा सकता है। तरीकों में से एक प्रकार () फ़ंक्शन का उपयोग करना है। टाइप () फ़ंक्शन, जब 3 पैरामीटर के साथ कॉल किया जाता है, तो मेटाक्लास बनाता है। पैरामीटर हैं: -

  1. कक्षा का नाम
  2. वर्ग द्वारा विरासत में मिली बेस क्लास वाले टुपल
  3. एक शब्दकोश जिसमें सभी वर्ग विधियाँ और वर्ग चर हैं

मेटाक्लास बनाने का एक अन्य तरीका 'मेटाक्लास' कीवर्ड शामिल है। मेटाक्लास को एक साधारण वर्ग के रूप में परिभाषित करें। विरासत में मिले वर्ग के मापदंडों में, पास करें metaclass=metaclass_name

निम्नलिखित स्थितियों में विशेष रूप से मेटाक्लास का उपयोग किया जा सकता है: -

  1. जब सभी उपवर्गों पर एक विशेष प्रभाव लागू किया जाना है
  2. वर्ग का स्वत: परिवर्तन (निर्माण पर) आवश्यक है
  3. एपीआई डेवलपर्स द्वारा
7
Swati Srivastava 20 जिंदा 2020, 09:59

ध्यान दें कि पायथन 3.6 में मेटाक्लास के लिए बहुत से सामान्य उपयोग के मामलों को बदलने के लिए एक नई डंडर विधि __init_subclass__(cls, **kwargs) पेश की गई थी। को तब कहा जाता है जब परिभाषित वर्ग का उपवर्ग बनाया जाता है। पायथन डॉक्स देखें।

12
Lars 3 मार्च 2020, 13:06

परिभाषा:
एक मेटाक्लास एक वर्ग है जिसके उदाहरण वर्ग हैं। जैसे "साधारण" वर्ग वर्ग के उदाहरणों के व्यवहार को परिभाषित करता है, एक मेटाक्लास कक्षाओं के व्यवहार और उनके उदाहरणों को परिभाषित करता है।

मेटाक्लास हर वस्तु उन्मुख प्रोग्रामिंग भाषा द्वारा समर्थित नहीं हैं। वे प्रोग्रामिंग भाषा, जो मेटाक्लास का समर्थन करती हैं, उन्हें लागू करने के तरीके में काफी भिन्नता है। पायथन उनका समर्थन कर रहा है।

कुछ प्रोग्रामर पायथन में मेटाक्लास को "समाधान की प्रतीक्षा या किसी समस्या की तलाश" के रूप में देखते हैं।

मेटाक्लास के लिए कई उपयोग के मामले हैं।

logging and profiling
interface checking
registering classes at creation time
automatically adding new methods
automatic property creation
proxies
automatic resource locking/synchronization.

मेटा वर्ग को परिभाषित करना:
यह अपने तर्कों की सामग्री को नई विधि में प्रिंट करेगा और प्रकार के परिणाम लौटाएगा।नया कॉल:

class LittleMeta(type):
    def __new__(cls, clsname, superclasses, attributedict):
        print("clsname: ", clsname)
        print("superclasses: ", superclasses)
        print("attributedict: ", attributedict)
        return type.__new__(cls, clsname, superclasses, attributedict)

हम निम्नलिखित उदाहरण में मेटाक्लास "लिटिलमेटा" का उपयोग करेंगे:

class S:
    pass    
class A(S, metaclass=LittleMeta):
    pass    
a = A()

आउटपुट:

clsname:  A
superclasses:  (<class '__main__.S'>,)
attributedict:  {'__module__': '__main__', '__qualname__': 'A'}
1
Neeraj Bansal 9 जुलाई 2020, 12:16

पायथन में एक metaclass एक वर्ग का एक वर्ग है जो परिभाषित करता है कि एक वर्ग कैसे व्यवहार करता है। एक वर्ग स्वयं metaclass का एक उदाहरण है। पायथन में एक वर्ग परिभाषित करता है कि कक्षा का उदाहरण कैसे व्यवहार करेगा। हम क्लास डेफिनिशन में metaclass कीवर्ड पास करके क्लास क्रिएशन प्रोसेस को कस्टमाइज कर सकते हैं। यह उस वर्ग को इनहेरिट करके भी किया जा सकता है जो इस कीवर्ड में पहले ही पास हो चुका है।

class MyMeta(type):
    pass

class MyClass(metaclass=MyMeta):
    pass

class MySubclass(MyClass):
    pass

हम देख सकते हैं कि MyMeta वर्ग का प्रकार type है और MyClass और MySubClass का प्रकार MyMeta है।

print(type(MyMeta))
print(type(MyClass))
print(type(MySubclass))

<class 'type'>
<class '__main__.MyMeta'>
<class '__main__.MyMeta'>

एक वर्ग को परिभाषित करते समय और कोई metaclass परिभाषित नहीं किया जाता है, डिफ़ॉल्ट प्रकार metaclass का उपयोग किया जाएगा। यदि एक metaclass दिया गया है और यह type() का उदाहरण नहीं है, तो इसे सीधे metaclass के रूप में प्रयोग किया जाता है।

मेटाक्लास को लॉगिंग, निर्माण के समय कक्षाओं के पंजीकरण और दूसरों के बीच प्रोफाइलिंग में लागू किया जा सकता है। वे काफी अमूर्त अवधारणाएं प्रतीत होती हैं, और आप सोच रहे होंगे कि क्या आपको उनका उपयोग करने की आवश्यकता है।

1
Usama Abdulrehman 15 जुलाई 2020, 07:34

मेटाक्लास एक प्रकार का वर्ग है जो परिभाषित करता है कि वर्ग कैसा व्यवहार करेगा या हम कह सकते हैं कि एक वर्ग स्वयं मेटाक्लास का एक उदाहरण है।

-12
Technical A.D. 29 मार्च 2020, 12:25
3
कृपया प्रासंगिक जानकारी जोड़ें ..आपकी टिप्पणियां भ्रमित करने वाली हैं
 – 
swastik
1 नवम्बर 2020, 21:39

पायथन में, एक मेटाक्लास एक उपवर्ग का एक उपवर्ग है जो यह निर्धारित करता है कि एक उपवर्ग कैसे व्यवहार करता है। एक वर्ग दूसरे मेटाक्लास का एक उदाहरण है। पायथन में, एक वर्ग निर्दिष्ट करता है कि कक्षा का उदाहरण कैसे व्यवहार करेगा।

चूंकि मेटाक्लास क्लास जनरेशन के प्रभारी होते हैं, इसलिए आप अतिरिक्त क्रियाओं या इंजेक्शन कोड को निष्पादित करके कक्षाओं के निर्माण के तरीके को बदलने के लिए अपने स्वयं के कस्टम मेटाक्लास लिख सकते हैं। कस्टम मेटाक्लास हमेशा महत्वपूर्ण नहीं होते हैं, लेकिन वे हो सकते हैं।

4
DrosnickX 21 अप्रैल 2021, 21:41

मैंने classutilities नामक पैकेज में मेटाक्लास के लिए एक दिलचस्प उपयोग का मामला देखा। यह जांचता है कि क्या सभी वर्ग चर ऊपरी केस प्रारूप में हैं (कॉन्फ़िगरेशन कक्षाओं के लिए एकीकृत तर्क रखना सुविधाजनक है), और जांचता है कि कक्षा में कोई इंस्टेंस स्तर विधियां नहीं हैं या नहीं। मेटाक्लेज़ के लिए एक और दिलचस्प उदाहरण जटिल परिस्थितियों (कई पर्यावरणीय चर के मूल्यों की जांच) के आधार पर यूनिटों को निष्क्रिय करना था।

4
Arthur MacMillan 13 जुलाई 2021, 01:53

शीर्ष उत्तर सही है

लेकिन पाठक इसी तरह नामित आंतरिक कक्षाओं के बारे में उत्तर खोजते हुए यहां आ रहे होंगे। वे लोकप्रिय पुस्तकालयों में मौजूद हैं, जैसे Django और WTForms

जैसा कि डेविड डब्ल्यू इस उत्तर के नीचे टिप्पणियों में बताते हैं, ये लाइब्रेरी-विशिष्ट विशेषताएं हैं और उन्नत, असंबंधित पायथन भाषा सुविधा के साथ भ्रमित नहीं होना चाहिए। समान नाम.

इसके बजाय, ये कक्षाओं के डिक्ट्स के भीतर नामस्थान हैं। वे पठनीयता के लिए आंतरिक कक्षाओं का उपयोग करके बनाए गए हैं।

इस उदाहरण में विशेष क्षेत्र, abstract लेखक मॉडल के क्षेत्रों से स्पष्ट रूप से अलग है।

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    class Meta:
        abstract = True

एक अन्य उदाहरण WTForms के दस्तावेज़ीकरण से है:

from wtforms.form import Form
from wtforms.csrf.session import SessionCSRF
from wtforms.fields import StringField

class MyBaseForm(Form):
    class Meta:
        csrf = True
        csrf_class = SessionCSRF

    name = StringField("name")

इस सिंटैक्स को पायथन प्रोग्रामिंग भाषा में विशेष उपचार नहीं मिलता है। Meta यहां एक कीवर्ड नहीं है, और मेटाक्लास व्यवहार को ट्रिगर नहीं करता है। बल्कि, Django और WTForms जैसे पैकेजों में तृतीय-पक्ष लाइब्रेरी कोड इस गुण को कुछ वर्गों और अन्य जगहों के कंस्ट्रक्टर्स में पढ़ता है।

इन घोषणाओं की उपस्थिति उन वर्गों के व्यवहार को संशोधित करती है जिनके पास ये घोषणाएँ हैं। उदाहरण के लिए, WTForms यह निर्धारित करने के लिए self.Meta.csrf पढ़ता है कि फ़ॉर्म को csrf फ़ील्ड की आवश्यकता है या नहीं।

4
Alex Waygood 21 सितंबर 2021, 14:49
1
यह एक Django-विशिष्ट विशेषता है जहां Meta नामक एक नेस्टेड वर्ग का एक विशेष अर्थ है। प्रश्न एक समान नाम के साथ एक असंबंधित पायथन भाषा सुविधा के बारे में है।
 – 
DavidW
29 अगस्त 2021, 13:40
- हैमिलियन ने इस पोस्ट का एक वीरतापूर्ण संपादन किया। मेरी राय में, अब यह काफी उपयोगी उत्तर है।
 – 
Alex Waygood
21 सितंबर 2021, 14:53
1
मैंने शायद संपादन को अस्वीकार कर दिया होगा (बहुत बड़ा बदलाव ...) लेकिन मैं देख सकता हूं कि यह कुछ ऐसा स्पष्ट करता है जो भ्रम की बात है, इसलिए यह शायद उपयोगी है। इसे ध्यान में रखते हुए, मैंने अपना डाउनवोट हटा दिया है।
 – 
DavidW
21 सितंबर 2021, 20:52
हाँ, मुझे लगता है कि आप इसे दोनों तरीकों से बहस कर सकते हैं। मैं आम तौर पर इतने बड़े संपादन को स्वीकृति नहीं दूंगा। लेकिन मुझे ऐसा लगा कि यह मूल पद की भावना के अनुरूप है, और ऐसा लग रहा था कि उचित मात्रा में काम एक नेक प्रयास में चला गया था (भ्रम के एक वैध बिंदु को स्पष्ट करते हुए), इसलिए अनुमोदन करने का निर्णय लिया।
 – 
Alex Waygood
21 सितंबर 2021, 21:45

इस देखो:

Python 3.10.0rc2 (tags/v3.10.0rc2:839d789, Sep  7 2021, 18:51:45) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Object:
...     pass
... 
>>> class Meta(type):
...     test = 'Worked!!!'
...     def __repr__(self):
...             return 'This is "Meta" metaclass'
... 
>>> class ObjectWithMetaClass(metaclass=Meta):
...     pass
... 
>>> Object or type(Object())
<class '__main__.Object'>
>>> ObjectWithMetaClass or type(ObjectWithMetaClass())
This is "Meta" metaclass
>>> Object.test
AttributeError: ...
>>> ObjectWithMetaClass.test
'Worked!!!'
>>> type(Object)
<class 'type'>
>>> type(ObjectWithMetaClass)
<class '__main__.Meta'>
>>> type(type(ObjectWithMetaClass))
<class 'type'>
>>> Object.__bases__
(<class 'object'>,)
>>> ObjectWithMetaClass.__bases__
(<class 'object'>,)
>>> type(ObjectWithMetaClass).__bases__
(<class 'type'>,)
>>> Object.__mro__
(<class '__main__.Object'>, <class 'object'>)
>>> ObjectWithMetaClass.__mro__
(This is "Meta" metaclass, <class 'object'>)
>>> 

दूसरे शब्दों में, जब कोई ऑब्जेक्ट नहीं बनाया गया था (ऑब्जेक्ट का प्रकार), तो हम मेटाक्लास देख रहे हैं।

0
Delta 3 अक्टूबर 2021, 19:06