एक वर्ग ब्लॉक एक शब्दकोश बनाने के लिए मोटे तौर पर वाक्य रचनात्मक चीनी है, और उसके बाद क्लास ऑब्जेक्ट बनाने के लिए मेटाक्लास का आह्वान किया जाता है।
यह:
class Foo(object):
__metaclass__ = FooMeta
FOO = 123
def a(self):
pass
काफी के रूप में यदि आप लिखा था बाहर आता है: (और वहाँ भी है वास्तविकता में
d = {}
d['__metaclass__'] = FooMeta
d['FOO'] = 123
def a(self):
pass
d['a'] = a
Foo = d.get('__metaclass__', type)('Foo', (object,), d)
केवल नाम स्थान प्रदूषण के बिना निर्धारित करने के लिए सभी ठिकानों के माध्यम से एक खोज मेटाक्लास, या मेटाक्लास संघर्ष है या नहीं, लेकिन मैं इसे अनदेखा कर रहा हूं)।
metaclass '__setattr__
नियंत्रित कर सकते हैं क्या होता है जब आप अपने उदाहरणों में से एक (कक्षा वस्तु) पर एक विशेषता सेट करने का प्रयास है, लेकिन वर्ग ब्लॉक के अंदर आपको लगता है कि नहीं कर रहे हैं, तो आप एक में डालने रहे हैं शब्दकोश वस्तु, इसलिए dict
कक्षा नियंत्रण क्या हो रहा है, आपका मेटाक्लास नहीं। तो आप भाग्य से बाहर हैं।
जब तक आप पाइथन 3.x का उपयोग नहीं कर रहे हैं! पायथन 3.x में आप मेटाक्लास पर __prepare__
क्लासमे विधि (या staticmethod) को परिभाषित कर सकते हैं, जो नियंत्रित करता है कि क्लास ब्लॉक में सेट किए गए गुणों को जमा करने से पहले ऑब्जेक्ट का उपयोग मेटाक्लास कन्स्ट्रक्टर को पास करने से पहले किया जाता है। डिफ़ॉल्ट __prepare__
बस एक सामान्य शब्दकोश दिखाए, लेकिन आप एक कस्टम dict की तरह वर्ग कि चाबी नए सिरे से परिभाषित करने की अनुमति नहीं है का निर्माण कर सकता है, और का उपयोग करें कि आपकी विशेषताएं जमा करने के लिए:
from collections import MutableMapping
class SingleAssignDict(MutableMapping):
def __init__(self, *args, **kwargs):
self._d = dict(*args, **kwargs)
def __getitem__(self, key):
return self._d[key]
def __setitem__(self, key, value):
if key in self._d:
raise ValueError(
'Key {!r} already exists in SingleAssignDict'.format(key)
)
else:
self._d[key] = value
def __delitem__(self, key):
del self._d[key]
def __iter__(self):
return iter(self._d)
def __len__(self):
return len(self._d)
def __contains__(self, key):
return key in self._d
def __repr__(self):
return '{}({!r})'.format(type(self).__name__, self._d)
class RedefBlocker(type):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
return SingleAssignDict()
def __new__(metacls, name, bases, sad):
return super().__new__(metacls, name, bases, dict(sad))
class Okay(metaclass=RedefBlocker):
a = 1
b = 2
class Boom(metaclass=RedefBlocker):
a = 1
b = 2
a = 3
इस रनिंग मुझे देता है:
Traceback (most recent call last):
File "/tmp/redef.py", line 50, in <module>
class Boom(metaclass=RedefBlocker):
File "/tmp/redef.py", line 53, in Boom
a = 3
File "/tmp/redef.py", line 15, in __setitem__
'Key {!r} already exists in SingleAssignDict'.format(key)
ValueError: Key 'a' already exists in SingleAssignDict
कुछ नोट: क्योंकि यह वें से पहले बुलाया जा रहा है
__prepare__
, एक classmethod
या staticmethod
हो गया है ई मेटाक्लास 'उदाहरण (आपकी कक्षा) मौजूद है।
type
अभी भी, एक असली dict
होने के लिए अपने तीसरे पैरामीटर की जरूरत है, ताकि आप एक __new__
विधि है कि करने के लिए एक सामान्य एक
- मैं
dict
subclassed किया जा सकता था SingleAssignDict
बदल देता है, जो शायद (2) से परहेज किया जाएगा करने के लिए है, लेकिन __setitem__
जैसे बुनियादी तरीकों के आपके ओवरराइड का सम्मान नहीं करते हैं, इस तरह से मैं वास्तव में ऐसा करने से नापसंद करता हूं कि update
जैसी गैर-मूलभूत विधियां कैसे हैं। तो मैं collections.MutableMapping
उपclass करना पसंद करता हूं और एक शब्दकोश लपेटता हूं।
- वास्तविक
Okay.__dict__
ऑब्जेक्ट एक सामान्य शब्दकोश है, क्योंकि इसे type
और type
द्वारा सेट किया गया था, जो इस प्रकार के शब्दकोश के बारे में परिष्कृत है। इसका मतलब है कि कक्षा निर्माण के बाद कक्षा विशेषताओं को ओवरराइट करना अपवाद नहीं बढ़ाता है। __new__
में सुपरक्लास कॉल के बाद आप __dict__
विशेषता को ओवरराइट कर सकते हैं यदि आप कक्षा ऑब्जेक्ट के शब्दकोश द्वारा मजबूर नो-ओवरराइटिंग को बनाए रखना चाहते हैं।
दुर्भाग्य से इस तकनीक का अजगर 2.x (मैं जाँच) में उपलब्ध नहीं है। __prepare__
विधि को लागू नहीं किया गया है, जो पाइथन 2.x के रूप में समझ में आता है मेटाक्लास क्लासब्लॉक में एक विशेष कीवर्ड की बजाय __metaclass__
जादू विशेषता द्वारा निर्धारित किया जाता है; जिसका मतलब है कि वर्ग ब्लॉक के लिए विशेषताओं को जमा करने के लिए उपयोग की जाने वाली dict वस्तु पहले से ही मेटाक्लास ज्ञात होने तक मौजूद है।
अजगर 2 की तुलना करें:
class Foo(object):
__metaclass__ = FooMeta
FOO = 123
def a(self):
pass
के बराबर होने के नाते:
d = {}
d['__metaclass__'] = FooMeta
d['FOO'] = 123
def a(self):
pass
d['a'] = a
Foo = d.get('__metaclass__', type)('Foo', (object,), d)
कहाँ metaclass आह्वान करने के लिए शब्दकोश से निर्धारित किया जाता है, अजगर 3 बनाम:
class Foo(metaclass=FooMeta):
FOO = 123
def a(self):
pass
होने के नाते लगभग बराबर:
d = FooMeta.__prepare__('Foo',())
d['Foo'] = 123
def a(self):
pass
d['a'] = a
Foo = FooMeta('Foo',(), d)
जहां उपयोग करने के लिए शब्दकोश मेटाक्लास से निर्धारित किया जाता है।
यह सटीक मुद्दा यही कारण है कि मेटालास वाक्यविन्यास py3 में बदल गया है! – SingleNegationElimination