উত্তর:
একটি মেটাক্লাস একটি শ্রেণীর শ্রেণি। একটি শ্রেণি নির্ধারণ করে যে শ্রেণীর একটি উদাহরণ (অর্থাত্ কোনও বস্তু) কীভাবে আচরণ করে যখন কোনও মেটাক্লাস একটি শ্রেণি কীভাবে আচরণ করে তা নির্ধারণ করে। একটি শ্রেণি একটি মেটাক্লাসের উদাহরণ।
পাইথন আপনি metaclasses (যেমন জন্য নির্বিচারে callables ব্যবহার করতে পারেন যদিও Jerub শো), ভাল পদ্ধতির এটি একটি প্রকৃত শ্রেণী নিজেই করা হয়। type
পাইথনের স্বাভাবিক মেটাক্লাস। type
এটি নিজেই একটি শ্রেণি, এবং এটি তার নিজস্ব ধরণের। আপনি type
পাইথনে খাঁটি জাতীয় কিছু পুনরায় তৈরি করতে সক্ষম হবেন না , তবে পাইথন একটু চিট করেন। পাইথনে আপনার নিজস্ব মেটাক্লাস তৈরি করতে আপনি সত্যিই কেবল সাবক্লাস করতে চান type
।
ক্লাস-কারখানা হিসাবে একটি মেটাক্লাস সবচেয়ে বেশি ব্যবহৃত হয়। আপনি যখন ক্লাসে কল করে কোনও বস্তু তৈরি করেন, পাইথন একটি নতুন শ্রেণি তৈরি করে (যখন এটি 'শ্রেণি' বিবৃতি কার্যকর করে) মেটাক্লাসে কল করে। সাধারণ __init__
এবং __new__
পদ্ধতিগুলির সাথে মিলিত , মেটাক্লাসগুলি আপনাকে ক্লাস তৈরি করার সময় 'অতিরিক্ত জিনিস' করার অনুমতি দেয় যেমন কিছু রেজিস্ট্রি দিয়ে নতুন ক্লাসটি রেজিস্ট্রেশন করা বা পুরোপুরি অন্য কোনও কিছু দিয়ে ক্লাসটি প্রতিস্থাপন করা।
যখন class
বিবৃতি কার্যকর, পাইথন প্রথম লাশ executes 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__
__metaclass__
পাইথন 3. পাইথন 3 ব্যবহার সমর্থিত নয় class MyObject(metaclass=MyType)
, দেখুন python.org/dev/peps/pep-3115 এবং নীচের উত্তর।
মেটাক্লাসগুলি বোঝার আগে আপনাকে পাইথনে ক্লাস করতে হবে। আর পাইথনের ক্লাসগুলি কী তা সম্পর্কে খুব অদ্ভুত ধারণা রয়েছে, স্মলটাক ভাষা থেকে ধার নেওয়া।
বেশিরভাগ ভাষায়, ক্লাসগুলি কেবলমাত্র কোডের টুকরো যা কীভাবে কোনও অবজেক্ট উত্পাদন করতে পারে তা বর্ণনা করে। পাইথনের ক্ষেত্রেও এটি সত্য:
>>> class ObjectCreator(object):
... pass
...
>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>
তবে ক্লাসগুলি পাইথনের চেয়ে বেশি। ক্লাসগুলিও অবজেক্ট।
হ্যাঁ, বস্তু
আপনি কীওয়ার্ডটি ব্যবহার করার সাথে সাথে class
পাইথন এটি সম্পাদন করে এবং একটি ওবিজেইসিটি তৈরি করে। নির্দেশনা
>>> class ObjectCreator(object):
... pass
...
স্মৃতিতে "অবজেক্টক্রিটর" নামে একটি বস্তু তৈরি করে।
এই অবজেক্ট (বর্গ) নিজেই অবজেক্ট তৈরি করতে সক্ষম (উদাহরণস্বরূপ), এবং এ কারণেই এটি একটি শ্রেণিবদ্ধ ।
তবে তবুও এটি একটি বস্তু এবং তাই:
উদাহরণ:
>>> print(ObjectCreator) # you can print a class because it's an object
<class '__main__.ObjectCreator'>
>>> def echo(o):
... print(o)
...
>>> echo(ObjectCreator) # you can pass a class as a parameter
<class '__main__.ObjectCreator'>
>>> print(hasattr(ObjectCreator, 'new_attribute'))
False
>>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
>>> print(hasattr(ObjectCreator, 'new_attribute'))
True
>>> print(ObjectCreator.new_attribute)
foo
>>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
>>> print(ObjectCreatorMirror.new_attribute)
foo
>>> print(ObjectCreatorMirror())
<__main__.ObjectCreator object at 0x8997b4c>
যেহেতু ক্লাসগুলি অবজেক্টস, তাই আপনি এগুলিকে যেকোন বস্তুর মতো তৈরি করতে পারেন।
প্রথমত, আপনি এটি ব্যবহার করে একটি ফাংশনে একটি ক্লাস তৈরি করতে পারেন class
:
>>> def choose_class(name):
... if name == 'foo':
... class Foo(object):
... pass
... return Foo # return the class, not an instance
... else:
... class Bar(object):
... pass
... return Bar
...
>>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>
তবে এটি এত গতিশীল নয়, যেহেতু আপনাকে এখনও পুরো ক্লাসটি নিজেই লিখতে হবে।
ক্লাসগুলি যেহেতু বস্তু, সেগুলি অবশ্যই কিছু দ্বারা উত্পন্ন করা উচিত।
আপনি class
কীওয়ার্ডটি ব্যবহার করার সময় পাইথন স্বয়ংক্রিয়ভাবে এই বস্তুটি তৈরি করে। পাইথনের বেশিরভাগ জিনিসের মতো এটি আপনাকে ম্যানুয়ালি করার একটি উপায় দেয়।
ফাংশন মনে আছে type
? ভাল পুরানো ফাংশন যা আপনাকে জানতে দেয় যে কোনও অবজেক্টটি কী ধরণের:
>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>
ভাল, type
একটি সম্পূর্ণ ভিন্ন ক্ষমতা আছে, এটি ফ্লাই ক্লাস তৈরি করতে পারে। type
কোনও শ্রেণীর বিবরণটিকে প্যারামিটার হিসাবে গ্রহণ করতে পারে এবং কোনও শ্রেণি ফিরে আসতে পারে।
(আমি জানি, এটি নির্বোধ যে আপনি যে প্যারামিটারগুলিতে পাস করেছেন সেই অনুযায়ী একই ফাংশনে দুটি সম্পূর্ণ আলাদা ব্যবহার থাকতে পারে Py পাইথনের পিছনের দিকের সামঞ্জস্যের কারণে এটি একটি সমস্যা)
type
এইভাবে কাজ করে:
type(name, bases, attrs)
কোথায়:
name
: ক্লাসের নামbases
: প্যারেন্ট ক্লাসের টিপল (উত্তরাধিকারের জন্য, খালি থাকতে পারে)attrs
: বৈশিষ্ট্য নাম এবং মান সমন্বিত অভিধানউদাহরণ:
>>> class MyShinyClass(object):
... pass
এইভাবে ম্যানুয়ালি তৈরি করা যেতে পারে:
>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>
আপনি লক্ষ্য করবেন যে আমরা ক্লাসের নাম এবং ক্লাসের রেফারেন্স ধরে রাখতে ভেরিয়েবল হিসাবে "মাই শাইনক্লাস" ব্যবহার করি। এগুলি আলাদা হতে পারে তবে জিনিসগুলিকে জটিল করার কোনও কারণ নেই।
type
শ্রেণীর বৈশিষ্ট্যগুলি সংজ্ঞায়িত করতে একটি অভিধান গ্রহণ করে। তাই:
>>> class Foo(object):
... bar = True
অনুবাদ করা যেতে পারে:
>>> Foo = type('Foo', (), {'bar':True})
এবং একটি সাধারণ শ্রেণি হিসাবে ব্যবহৃত:
>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True
এবং অবশ্যই, আপনি এটির উত্তরাধিকারী হতে পারেন, সুতরাং:
>>> class FooChild(Foo):
... pass
হবে:
>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True
শেষ পর্যন্ত আপনি আপনার ক্লাসে পদ্ধতি যুক্ত করতে চাইবেন। যথাযথ স্বাক্ষর সহ একটি ফাংশন কেবল সংজ্ঞায়িত করুন এবং এটিকে একটি অ্যাট্রিবিউট হিসাবে নির্ধারণ করুন।
>>> def echo_bar(self):
... print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True
আপনি সাধারণভাবে তৈরি ক্লাস অবজেক্টে মেথড যুক্ত করার মতো, ক্লাসিকভাবে ক্লাস তৈরির পরে আপনি আরও বেশি পদ্ধতি যুক্ত করতে পারেন।
>>> def echo_bar_more(self):
... print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True
আপনি দেখতে পাচ্ছেন আমরা কোথায় যাচ্ছি: পাইথনে, ক্লাসগুলি হ'ল বস্তু এবং আপনি গতিবেগে ফ্লাইতে একটি ক্লাস তৈরি করতে পারেন।
আপনি কীওয়ার্ডটি ব্যবহার করার সময় পাইথন class
এটি করে এবং এটি একটি মেটাক্লাস ব্যবহার করে করে।
মেটাচ্লাসগুলি এমন 'স্টাফ' যা ক্লাস তৈরি করে।
আপনি অবজেক্ট তৈরি করার জন্য ক্লাস সংজ্ঞায়িত করেছেন, তাই না?
তবে আমরা শিখেছি পাইথন ক্লাসগুলি বস্তু।
ওয়েল, মেটাক্লাসগুলি এই জিনিসগুলি তৈরি করে। এগুলি ক্লাসের ক্লাস, আপনি তাদের এইভাবে চিত্রিত করতে পারেন:
MyClass = MetaClass()
my_object = MyClass()
আপনি দেখেছেন যে type
আপনাকে এরকম কিছু করতে দেয়:
MyClass = type('MyClass', (), {})
কারণ ফাংশনটি type
আসলে একটি মেটাক্লাস। type
পাইথন হল মেটাক্লাস যা পর্দার আড়ালে সমস্ত শ্রেণি তৈরি করে।
এখন আপনি ভাবছেন যে হেক কেন এটি ছোট হাতের অক্ষরে লেখা হয়, এবং না Type
?
ভাল, আমি অনুমান করি এটি একটি ধারাবাহিকতার বিষয়, str
যে স্ট্রিংগুলি স্ট্রিং অবজেক্ট তৈরি করে এবং int
যে শ্রেণীটি পূর্ণসংখ্যার বস্তু তৈরি করে। type
কেবল শ্রেণি যা শ্রেণি অবজেক্ট তৈরি করে।
আপনি দেখতে পারেন যে __class__
গুণটি পরীক্ষা করে ।
সমস্ত কিছু, এবং আমার অর্থ সমস্ত কিছুই পাইথনের একটি বস্তু। এর মধ্যে অন্তর্নির্মিত স্ট্রিং, ফাংশন এবং ক্লাস রয়েছে। এগুলির সবই বস্তু are এবং এগুলি সমস্তই একটি শ্রেণী থেকে তৈরি করা হয়েছে:
>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
এখন, কি __class__
কোনো __class__
?
>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>
সুতরাং, একটি মেটাক্লাস কেবল স্টাফ যা শ্রেণি অবজেক্ট তৈরি করে।
আপনি যদি চান তবে এটিকে একটি 'ক্লাস ফ্যাক্টরি' বলতে পারেন।
type
পাইথনটি অন্তর্নির্মিত মেটাক্লাস ব্যবহার করে তবে অবশ্যই আপনি নিজের মেটাক্লাস তৈরি করতে পারেন।
__metaclass__
গুণপাইথন 2 এ, আপনি __metaclass__
কোনও ক্লাস লেখার সময় একটি বৈশিষ্ট্য যুক্ত করতে পারেন (পাইথন 3 সিনট্যাক্সের পরবর্তী বিভাগটি দেখুন):
class Foo(object):
__metaclass__ = something...
[...]
আপনি যদি এটি করেন তবে পাইথন ক্লাস তৈরি করতে মেটাক্লাস ব্যবহার করবে Foo
।
সাবধান, এটি কৌতূহলী।
আপনি class Foo(object)
প্রথমে লিখুন , কিন্তু ক্লাস অবজেক্টটি Foo
এখনও মেমরিতে তৈরি হয়নি।
পাইথন __metaclass__
ক্লাস সংজ্ঞায় সন্ধান করবে । এটি যদি এটির সন্ধান করে তবে এটি বস্তু শ্রেণি তৈরি করতে এটি ব্যবহার করবে Foo
। যদি এটি না হয় তবে এটি type
ক্লাস তৈরি করতে ব্যবহার করবে
।
কয়েকবার পড়ুন।
যখন তুমি কর:
class Foo(Bar):
pass
পাইথন নিম্নলিখিতগুলি করে:
কোন __metaclass__
বৈশিষ্ট্য আছে Foo
?
যদি হ্যাঁ, মেমোরিতে একটি শ্রেণীর অবজেক্ট তৈরি করুন (আমি বললাম একটি শ্রেণীর অবজেক্ট, এখানে আমার সাথে থাকুন), নামটি Foo
কী রয়েছে তা দিয়ে নামটি দিয়ে __metaclass__
।
পাইথন যদি এটি খুঁজে না পায় তবে এটি মডুল স্তরের দিকে __metaclass__
সন্ধান করবে __metaclass__
এবং এটি করার চেষ্টা করবে (তবে কেবল এমন ক্লাসগুলির জন্য যা কিছু উত্তরাধিকারসূত্রে পায় না, মূলত পুরানো-শৈলিক ক্লাসগুলি)।
তারপরে এটি যদি কোনও কিছু না খুঁজে __metaclass__
পায়, তবে শ্রেণি অবজেক্ট তৈরি করতে এটির Bar
(প্রথম পিতা-মাতার) নিজস্ব মেটাগ্লাস (যা ডিফল্ট হতে পারে type
) ব্যবহার করবে।
এখানে সাবধান থাকুন যে __metaclass__
বৈশিষ্টটি উত্তরাধিকার সূত্রে প্রাপ্ত হবে না, পিতামাতার ( Bar.__class__
) এর মেটাক্লাস হবে। যদি Bar
একটি ব্যবহৃত __metaclass__
যে নির্মিত অ্যাট্রিবিউট Bar
সঙ্গে type()
(এবং type.__new__()
), উপশ্রেণী যে আচরণ উত্তরাধিকারী করা হবে না।
এখন বড় প্রশ্ন হ'ল আপনি কী লাগাতে পারেন __metaclass__
?
উত্তরটি হল: এমন কিছু যা একটি বর্গ তৈরি করতে পারে।
এবং কি একটি বর্গ তৈরি করতে পারেন? type
, বা এমন কিছু যা সাবক্লাস করে বা ব্যবহার করে।
মেটাক্লাস সেট করার সিনট্যাক্সটি পাইথন 3 এ পরিবর্তন করা হয়েছে:
class Foo(object, metaclass=something):
...
উদাহরণস্বরূপ __metaclass__
, বেস শ্রেণীর তালিকার কোনও কীওয়ার্ড আর্গুমেন্টের পক্ষে বৈশিষ্ট্যটি আর ব্যবহার করা হয় না।
মেটাক্লাসগুলির আচরণ যদিও মূলত একইরকম থাকে ।
পাইথন 3-তে মেটাক্লাসগুলিতে একটি জিনিস যুক্ত হল আপনি কী-ওয়ার্ড-আর্গুমেন্ট হিসাবে বৈশিষ্ট্যগুলি একটি মেটাক্লাসে পাস করতে পারেন:
class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
...
পাইথন কীভাবে এটি পরিচালনা করে তার জন্য নীচের বিভাগটি পড়ুন।
একটি মেটাক্লাসের মূল উদ্দেশ্য বর্গটি তৈরি হওয়ার পরে স্বয়ংক্রিয়ভাবে পরিবর্তন করা।
আপনি সাধারণত এটি পিপিআইয়ের জন্য করেন যেখানে আপনি বর্তমান প্রসঙ্গে মেলে এমন ক্লাস তৈরি করতে চান।
একটি মূর্খ উদাহরণটির কল্পনা করুন, যেখানে আপনি সিদ্ধান্ত নিয়েছেন যে আপনার মডিউলের সমস্ত শ্রেণীর উচ্চতর অক্ষরে লেখা উচিত written এটি করার বিভিন্ন উপায় রয়েছে তবে একটি উপায় হ'ল __metaclass__
মডিউল স্তরে সেট করা।
এই মডিউলক্লাসটি ব্যবহার করে এই মডিউলটির সমস্ত শ্রেণি তৈরি করা হবে, এবং আমাদের কেবলমাত্র মেটাক্লাসকে সমস্ত বৈশিষ্ট্যকে বড় হাতের দিকে পরিণত করতে বলতে হবে।
ভাগ্যক্রমে, __metaclass__
আসলে যে কোনও কলযোগ্য হতে পারে, এটি একটি আনুষ্ঠানিক শ্রেণি হওয়ার দরকার নেই (আমি জানি, এর নামে 'শ্রেণি'র কিছু রয়েছে এমন একটি শ্রেণি হওয়ার দরকার নেই, ফিগারে যান ... তবে এটি সহায়ক)।
সুতরাং আমরা একটি ফাংশন ব্যবহার করে একটি সাধারণ উদাহরণ দিয়ে শুরু করব।
# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attrs):
"""
Return a class object, with the list of its attribute turned
into uppercase.
"""
# pick up any attribute that doesn't start with '__' and uppercase it
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in future_class_attrs.items()
}
# let `type` do the class creation
return type(future_class_name, future_class_parents, uppercase_attrs)
__metaclass__ = upper_attr # this will affect all classes in the module
class Foo(): # global __metaclass__ won't work with "object" though
# but we can define __metaclass__ here instead to affect only this class
# and this will work with "object" children
bar = 'bip'
আসুন পরীক্ষা করে দেখুন:
>>> hasattr(Foo, 'bar')
False
>>> hasattr(Foo, 'BAR')
True
>>> Foo.BAR
'bip'
এখন, আসুন ঠিক একই জিনিস করা যাক, তবে একটি মেটাক্লাসের জন্য একটি আসল বর্গ ব্যবহার করা:
# remember that `type` is actually a class like `str` and `int`
# so you can inherit from it
class UpperAttrMetaclass(type):
# __new__ is the method called before __init__
# it's the method that creates the object and returns it
# while __init__ just initializes the object passed as parameter
# you rarely use __new__, except when you want to control how the object
# is created.
# here the created object is the class, and we want to customize it
# so we override __new__
# you can do some stuff in __init__ too if you wish
# some advanced use involves overriding __call__ as well, but we won't
# see this
def __new__(upperattr_metaclass, future_class_name,
future_class_parents, future_class_attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in future_class_attrs.items()
}
return type(future_class_name, future_class_parents, uppercase_attrs)
আসুন উপরে লেখাটি আবার লিখুন, তবে সংক্ষিপ্ততর এবং আরও বাস্তবসম্মত পরিবর্তনশীল নামগুলির সাথে এখনই আমরা জানি যে এর অর্থ কী:
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in attrs.items()
}
return type(clsname, bases, uppercase_attrs)
আপনি অতিরিক্ত যুক্তি খেয়াল করতে পারেন cls
। এটি সম্পর্কে বিশেষ কিছু নেই: __new__
সর্বদা প্রথম পরামিতি হিসাবে এটি নির্ধারিত শ্রেণিটি গ্রহণ করে। আপনার self
যেমন সাধারণ পদ্ধতি রয়েছে যা প্রথম প্যারামিটার হিসাবে উদাহরণ গ্রহণ করে, বা শ্রেণি পদ্ধতিগুলির জন্য সংজ্ঞায়িত শ্রেণি।
তবে এটি সঠিক ওওপি নয়। আমরা type
সরাসরি কল করছি এবং আমরা পিতামাতারকে ওভাররাইড বা কল করছি না __new__
। পরিবর্তে এটি করা যাক:
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in attrs.items()
}
return type.__new__(cls, clsname, bases, uppercase_attrs)
আমরা এটি ব্যবহার করে আরও পরিষ্কার করে তুলতে পারি super
, যা উত্তরাধিকারকে সহজ করবে (কারণ হ্যাঁ, আপনি মেটাক্লাসগুলি পেতে পারেন, মেটাক্লাস থেকে উত্তরাধিকার সূত্রে প্রাপ্ত, টাইপ থেকে উত্তরাধিকার সূত্রে):
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in attrs.items()
}
return super(UpperAttrMetaclass, cls).__new__(
cls, clsname, bases, uppercase_attrs)
ওহ, এবং পাইথন 3-এ আপনি কীওয়ার্ড আর্গুমেন্টগুলির সাথে এই কলটি করেন যদি:
class Foo(object, metaclass=MyMetaclass, kwarg1=value1):
...
এটি এটি ব্যবহার করার জন্য এটি মেটাক্লাসে অনুবাদ করে:
class MyMetaclass(type):
def __new__(cls, clsname, bases, dct, kwargs1=default):
...
এটাই. মেটাক্লাস সম্পর্কে আসলে কিছুই নেই nothing
কোডটি মেটাক্লাসগুলি ব্যবহার করার জটিলতার পিছনে কারণগুলি মেটাক্লাসগুলি নয়, কারণ আপনি সাধারণত অন্তর্নিম্নকরণের উপর নির্ভরশীল বাঁকানো জিনিসগুলি করতে, উত্তরাধিকারের হেরফের করা, বার্স __dict__
ইত্যাদির জন্য মেটাক্লাস ব্যবহার করেন because
প্রকৃতপক্ষে, কালো জাদু করতে মেটাক্লাসগুলি বিশেষত কার্যকর এবং তাই জটিল স্টাফ। তবে তারা নিজেরাই সহজ:
যেহেতু __metaclass__
যে কোনও কলযোগ্য গ্রহণ করতে পারে তাই আপনি কেন ক্লাসটি ব্যবহার করবেন কেননা এটি স্পষ্টতই জটিল?
এটি করার বিভিন্ন কারণ রয়েছে:
UpperAttrMetaclass(type)
, আপনি কী অনুসরণ করবেন তা আপনি জানেন__new__
, __init__
এবং __call__
। যা আপনাকে বিভিন্ন স্টাফ করার অনুমতি দেবে। এমনকি যদি আপনি সাধারণত এটি করতে পারেন তবে __new__
কিছু লোক ব্যবহার করে আরও স্বাচ্ছন্দ্য বোধ করেন __init__
।এখন বড় প্রশ্ন। আপনি কেন কিছু অস্পষ্ট ত্রুটিযুক্ত প্রবণ বৈশিষ্ট্যটি ব্যবহার করবেন?
ভাল, সাধারণত আপনি না:
মেটাক্লাসগুলি গভীর যাদু যা 99% ব্যবহারকারীদের কখনও চিন্তা করা উচিত নয়। আপনার যদি তাদের প্রয়োজন হয় কিনা তা আপনি যদি ভাবেন তবে আপনারা (আসলে যাঁদের প্রকৃত প্রয়োজন তাদের অবশ্যই প্রয়োজন যে তাদের তাদের প্রয়োজন know তারা জানেন, এবং কেন এটি সম্পর্কে কোনও ব্যাখ্যা প্রয়োজন নেই)।
পাইথন গুরু টিম পিটার্স
একটি মেটাক্লাসের প্রধান ব্যবহারের ক্ষেত্রটি একটি এপিআই তৈরি করছে। এর একটি সাধারণ উদাহরণ জ্যাঙ্গো ওআরএম। এটি আপনাকে এরকম কিছু সংজ্ঞায়িত করতে দেয়:
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
তবে আপনি যদি এটি করেন:
person = Person(name='bob', age='35')
print(person.age)
এটি কোনও IntegerField
জিনিস ফেরত দেবে না । এটি একটি ফিরে আসবে int
এবং এটি সরাসরি ডাটাবেস থেকেও নিতে পারে।
এটি সম্ভব হয়েছে কারণ এটি models.Model
সংজ্ঞায়িত করে __metaclass__
এবং এটি এমন কিছু জাদু ব্যবহার করে যা Person
আপনাকে স্রেফ সরল বিবৃতি দিয়ে সংজ্ঞায়িত করে একটি জটিল হুককে একটি ডাটাবেস ক্ষেত্রে পরিণত করবে।
জ্যাঙ্গো একটি সাধারণ এপিআই প্রকাশ করে এবং মেটাক্লাস ব্যবহার করে, পর্দার পিছনে আসল কাজটি করার জন্য এই এপিআই থেকে কোডটি পুনরায় তৈরি করে জটিল কিছু জটিল দেখায়।
প্রথমত, আপনি জানেন যে ক্লাসগুলি এমন বস্তু যা দৃষ্টান্ত তৈরি করতে পারে।
আসলে, ক্লাসগুলি নিজেরাই দৃষ্টান্ত। মেটাক্লাসের।
>>> class Foo(object): pass
>>> id(Foo)
142630324
পাইথনে সবকিছুই একটি বস্তু এবং সেগুলি হয় ক্লাসের উদাহরণ বা মেটাক্লাসগুলির উদাহরণ।
ছাড়া type
।
type
আসলে এটি নিজস্ব মেটাগ্লাস। এটি খাঁটি পাইথনে পুনরুত্পাদন করতে পারে এমন কিছু নয় এবং বাস্তবায়ন স্তরে কিছুটা প্রতারণা করেই এটি করা হয়।
দ্বিতীয়ত, মেটাক্লাসগুলি জটিল। আপনি এগুলি খুব সাধারণ শ্রেণীর পরিবর্তনের জন্য ব্যবহার করতে নাও চান। দুটি ভিন্ন কৌশল ব্যবহার করে আপনি ক্লাস পরিবর্তন করতে পারেন:
আপনার যখন শ্রেণি পরিবর্তনের প্রয়োজন হয় তার 99% সময়, আপনি এগুলি ব্যবহার করে ভাল।
তবে 98% সময়, আপনার কোনও শ্রেণিবিন্যাসের প্রয়োজন হয় না।
models.Model
এটি ব্যবহার না করে __metaclass__
বরং class Model(metaclass=ModelBase):
কোনও ModelBase
শ্রেণীর রেফারেন্স করার জন্য যা পরে উল্লিখিত মেটাগ্লাস যাদু করে। দুর্দান্ত পোস্ট! এখানে জ্যাঙ্গো উত্স: github.com/django/django/blob/master/django/db/models/…
__metaclass__
বৈশিষ্টটি উত্তরাধিকার সূত্রে প্রাপ্ত হবে না, পিতামাতার ( Bar.__class__
) এর মেটাক্লাস হবে। যদি Bar
একটি ব্যবহৃত __metaclass__
গুণ যা সৃষ্টি করেছেন Bar
সঙ্গে type()
(এবং type.__new__()
), উপশ্রেণী অধিকার পাইবে না যে আচরণ >> -। আপনি / কেউ একটু গভীর এই উত্তরণ দয়া করে ব্যাখ্যা করুন যায়নি?
Now you wonder why the heck is it written in lowercase, and not Type?
- ভাল কারণ এটি সি তে বাস্তবায়িত হয়েছে - একই কারণেই ডিফল্টডিক্টট্ট ছোট হাতের অক্ষর থাকে যখন অর্ডারডটিক্ট (পাইথন 2 এ) সাধারণ ক্যামেলকেস হয়
দ্রষ্টব্য, এই উত্তরটি পাইথন ২.x এর জন্য যেমনটি ২০০৮ সালে লেখা হয়েছিল, মেটাক্লাসগুলি 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
অন্যরা ব্যাখ্যা করেছেন যে কীভাবে মেটাক্লাসগুলি কাজ করে এবং কীভাবে পাইথন টাইপ সিস্টেমে ফিট করে। তারা কী ব্যবহার করতে পারে তার একটি উদাহরণ এখানে। আমি একটি পরীক্ষার কাঠামোয় লিখেছি, আমি ক্লাসগুলি যে ক্রমে সংজ্ঞায়িত করা হয়েছিল সেটির ট্র্যাক রাখতে চেয়েছিলাম, যাতে পরে আমি এই ক্রমে তাদের ইনস্ট্যান্ট করতে পারি। আমি এটি একটি মেটাক্লাস ব্যবহার করে সবচেয়ে সহজ বলে মনে করি।
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
যা ক্লাসগুলি সংজ্ঞায়িত করা হয়েছিল এমন ক্রম রেকর্ড করে।
__init__(self)
কথা type(self)._order = MyBase.counter; MyBase.counter += 1
?
মেটাক্লাসগুলির জন্য একটি ব্যবহার স্বয়ংক্রিয়ভাবে একটি দৃষ্টিতে নতুন বৈশিষ্ট্য এবং পদ্ধতি যুক্ত করছে।
উদাহরণস্বরূপ, আপনি জ্যাঙ্গো মডেলগুলির দিকে নজর দিলে তাদের সংজ্ঞাটি কিছুটা বিভ্রান্ত দেখাচ্ছে looks দেখে মনে হচ্ছে আপনি কেবল শ্রেণিবদ্ধের বৈশিষ্ট্যই সংজ্ঞায়িত করছেন:
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
যাইহোক, রানটাইম সময়ে ব্যক্তি অবজেক্টগুলি সমস্ত ধরণের দরকারী পদ্ধতিতে পূর্ণ হয়। কিছু আশ্চর্যজনক metaclassery জন্য উত্স দেখুন ।
আমি মনে করি মেটাক্লাস প্রোগ্রামিংয়ের ওএনল্যাম্পের ভূমিকাটি বেশ ভাল লেখা আছে এবং ইতিমধ্যে বেশ কয়েক বছর বয়সী হওয়া সত্ত্বেও বিষয়টিতে সত্যই একটি ভাল পরিচয় দেয়।
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html ( https://web.archive.org/web/20080206005253/http://www.onlamp এ সংরক্ষণাগারভুক্ত করা হয়েছে । com / পাব / এ / পাইথন / 2003/04/17 / মেটাক্লাসস html )
সংক্ষেপে: একটি শ্রেণি হ'ল উদাহরণ তৈরির জন্য একটি নীলনকশা, একটি মেটাক্লাস একটি শ্রেণি তৈরির একটি নীলনকশা। এটি সহজেই দেখা যায় যে পাইথন ক্লাসে এই আচরণটি সক্ষম করার জন্য প্রথম শ্রেণির অবজেক্টগুলিও হওয়া দরকার।
আমি নিজেই একটি লিখিনি, তবে আমি মনে করি যে জ্যাঙ্গো কাঠামোর মধ্যে মেটাক্লাসগুলির সর্বোত্তম ব্যবহারগুলির একটি দেখা যায় । মডেল ক্লাসগুলি একটি নতুন মডেল বা ফর্ম ক্লাস লেখার একটি ঘোষণামূলক স্টাইল সক্ষম করতে একটি মেটাক্লাস পদ্ধতির ব্যবহার করে। মেটাক্লাস ক্লাস তৈরি করার সময়, সমস্ত সদস্য নিজেই ক্লাসটি কাস্টমাইজ করার সম্ভাবনা পান।
বাকীটি যা বলার আছে তা হ'ল: যদি আপনি না জানেন যে মেটাচলসগুলি কী, তবে আপনার তাদের প্রয়োজন হবে না এমন সম্ভাবনা 99%।
মেটাক্লাস কি? আপনি তাদের জন্য কি ব্যবহার করবেন?
টিএলডিআর: একটি মেটাক্লাস ক্লাসের জন্য যেমন ক্লাস ইনস্ট্যান্টিয়েট করে এবং উদাহরণের জন্য আচরণের সংজ্ঞা দেয় তেমনি আচরণের সংজ্ঞা দেয় এবং সংজ্ঞা দেয়।
সুডোকোড:
>>> 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'>
আপনি যখন কোনও শ্রেণির সংজ্ঞা লেখেন এবং পাইথন এটি কার্যকর করে, এটি শ্রেণি অবজেক্টটি ইনস্ট্যান্ট করার জন্য একটি মেটাক্লাস ব্যবহার করে (যা পরিবর্তে that শ্রেণীর উদাহরণগুলি ইনস্ট্যান্ট করতে ব্যবহৃত হবে)।
কাস্টম অবজেক্টের দৃষ্টান্তগুলি কীভাবে আচরণ করে তা পরিবর্তনের জন্য আমরা যেমন ক্লাস সংজ্ঞা ব্যবহার করতে পারি, তেমনি ক্লাস অবজেক্টের আচরণের পদ্ধতি পরিবর্তন করতে আমরা একটি মেটাক্লাস শ্রেণির সংজ্ঞা ব্যবহার করতে পারি।
তারা কি জন্য ব্যবহার করা যেতে পারে? ডক্স থেকে :
মেটাক্লাসগুলির সম্ভাব্য ব্যবহারগুলি সীমাহীন। অনুসন্ধান করা হয়েছে এমন কিছু ধারণার মধ্যে রয়েছে লগিং, ইন্টারফেস চেকিং, স্বয়ংক্রিয় প্রতিনিধি, স্বয়ংক্রিয় সম্পত্তি তৈরি, প্রক্সি, ফ্রেমওয়ার্ক এবং স্বয়ংক্রিয় সংস্থান লকিং / সিঙ্ক্রোনাইজেশন।
তবুও, একেবারে প্রয়োজনীয় না হলে সাধারণত মেটাক্লাস ব্যবহার করা এড়াতে ব্যবহারকারীদের জন্য উত্সাহ দেওয়া হয়।
আপনি যখন ক্লাস সংজ্ঞা লেখেন, উদাহরণস্বরূপ,
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__
এগুলি বাদ দিয়ে পারি example উদাহরণস্বরূপ:
>>> 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__
)।
__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')
দ্রষ্টব্য, এই উদাহরণটি ডকুমেন্টেশন থেকে অভিযোজিত হয়েছিল - স্ট্যান্ডার্ড লাইব্রেরিতে নতুন এনাম এটি করে ।
সুতরাং আমরা যা করেছি তা ক্লাস তৈরি করে একটি মেটাক্লাস ইনস্ট্যান্টিয়েট করা হয়েছিল। আমরা মেটাক্লাসকে অন্য কোনও ক্লাসের মতো আচরণ করতে পারি। এটিতে একটি পদ্ধতি সমাধানের আদেশ রয়েছে:
>>> 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>})
পাইথন 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')
দ্রষ্টব্য : এই উদাহরণটি যথেষ্ট সহজ এটি কোনও শ্রেণি সাজসজ্জারের সাথেও সম্পন্ন করা যেতে পারে তবে সম্ভবত একটি প্রকৃত মেটাক্লাস আরও অনেক কিছু করবে।
রেফারেন্সের জন্য 'বৈধতা টাইপ' শ্রেণি:
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
__set_name__(cls, name)
বর্ণনাকারীতে ValidateType
নাম সেট করতে বর্ণনাকারী ( ) ব্যবহার করতে পারেন ( self.name
এবং এই ক্ষেত্রেও self.attr
)। এই নির্দিষ্ট সাধারণ ব্যবহারের ক্ষেত্রে মেটাচ্লাসে ডুবতে হবে না (পিইপি 487 দেখুন) এটি যুক্ত করা হয়েছিল।
__call__()
শ্রেণীর উদাহরণ তৈরি করার সময় একটি মেটাক্লাস ' পদ্ধতির ভূমিকাআপনি যদি কয়েক মাসেরও বেশি সময় পাইথন প্রোগ্রামিং করে থাকেন তবে আপনি শেষ পর্যন্ত এমন কোডের উপর হোঁচট খেয়ে যাবেন:
# define a class
class SomeClass(object):
# ...
# some definition here ...
# ...
# create an instance of it
instance = SomeClass()
# then call the object as if it's a function
result = instance('foo', 'bar')
পরবর্তীটি সম্ভব যখন আপনি __call__()
ক্লাসে যাদু পদ্ধতিটি প্রয়োগ করেন ।
class SomeClass(object):
# ...
# some definition here ...
# ...
def __call__(self, foo, bar):
return bar + foo
__call__()
পদ্ধতি যখন একটি ক্লাসের একটা নিদর্শন একটি callable হিসাবে ব্যবহার করা হয় প্রার্থনা করা হয়। তবে আমরা পূর্বের উত্তরগুলি থেকে দেখেছি যে একটি শ্রেণি নিজেই একটি মেটাক্লাসের উদাহরণ, তাই যখন আমরা ক্লাসটিকে কলযোগ্য হিসাবে ব্যবহার করি (যখন আমরা এটির উদাহরণ তৈরি করি তখন) আমরা প্রকৃতপক্ষে এর মেটাক্লাস __call__()
পদ্ধতিটি কল করি । এই মুহুর্তে বেশিরভাগ পাইথন প্রোগ্রামাররা কিছুটা বিভ্রান্ত হয় কারণ তাদের বলা হয়েছিল যে এই জাতীয় কোনও ইভেন্ট তৈরি করার সময় instance = SomeClass()
আপনি এর __init__()
পদ্ধতিটি কল করছেন । এমন কেউ কেউ একটু গভীর খনন করেছি জানি যে সামনে __init__()
আছে __new__()
। ঠিক আছে, আজ সত্যের আরও একটি স্তর প্রকাশিত হচ্ছে, __new__()
মেটাক্লাসের আগে ' __call__()
।
একটি ক্লাসের উদাহরণ তৈরির দৃষ্টিকোণ থেকে পদ্ধতি কল চেইনটি অধ্যয়ন করি।
এটি এমন একটি মেটাক্লাস যা কোনও দৃষ্টান্ত তৈরি হওয়ার ঠিক মুহুর্তে এবং যে মুহূর্তে এটি ফিরে আসবে তা লগ করে।
class Meta_1(type):
def __call__(cls):
print "Meta_1.__call__() before creating an instance of ", cls
instance = super(Meta_1, cls).__call__()
print "Meta_1.__call__() about to return instance."
return instance
এটি এমন একটি শ্রেণি যা সেই মেটাক্লাস ব্যবহার করে
class Class_1(object):
__metaclass__ = Meta_1
def __new__(cls):
print "Class_1.__new__() before creating an instance."
instance = super(Class_1, cls).__new__(cls)
print "Class_1.__new__() about to return instance."
return instance
def __init__(self):
print "entering Class_1.__init__() for instance initialization."
super(Class_1,self).__init__()
print "exiting Class_1.__init__()."
এবং এখন এর একটি উদাহরণ তৈরি করা যাক Class_1
instance = Class_1()
# Meta_1.__call__() before creating an instance of <class '__main__.Class_1'>.
# Class_1.__new__() before creating an instance.
# Class_1.__new__() about to return instance.
# entering Class_1.__init__() for instance initialization.
# exiting Class_1.__init__().
# Meta_1.__call__() about to return instance.
লক্ষ্য করুন যে উপরের কোডটি কার্যগুলি লগ করার চেয়ে বেশি কিছু করে না। প্রতিটি পদ্ধতি প্রকৃত কাজটি তার পিতামাতার প্রয়োগের জন্য প্রতিনিধিত্ব করে, এভাবে ডিফল্ট আচরণ রাখে। যেহেতু type
হয় Meta_1
এর পিতা বা মাতা শ্রেণী ( type
ডিফল্ট পিতা বা মাতা ক্লাসের অধীনে একটি ক্লাস হচ্ছে) এবং উপরে আউটপুট ক্রম ক্রম বিবেচনা করা, আমরা এখন কি ছদ্ম বাস্তবায়ন হবে সম্বন্ধে একটা সূত্র আছে type.__call__()
:
class type:
def __call__(cls, *args, **kwarg):
# ... maybe a few things done to cls here
# then we call __new__() on the class to create an instance
instance = cls.__new__(cls, *args, **kwargs)
# ... maybe a few things done to the instance here
# then we initialize the instance with its __init__() method
instance.__init__(*args, **kwargs)
# ... maybe a few more things done to instance here
# then we return it
return instance
আমরা দেখতে পাচ্ছি যে মেটাক্লাস ' __call__()
পদ্ধতিটি প্রথমে বলা হয়। এরপরে এটি ক্লাসের __new__()
পদ্ধতিতে উদাহরণটি তৈরি করে উদাহরণের সূচনা করে __init__()
। এটি হ'ল শেষ পর্যন্ত উদাহরণটি ফেরত দেয়।
উপরের আলোচনা থেকে এটা ডালপালা যে ক্লাসের অধীনে একটি ক্লাস ' __call__()
এছাড়াও থাকুক বা না থাকুক একটা কল সিদ্ধান্ত নিতে সুযোগ দেওয়া হয় Class_1.__new__()
বা Class_1.__init__()
অবশেষে তৈরি করা হবে। মৃত্যুদন্ড কার্যকর হওয়ার পরে এটি আসলে এমন কোনও জিনিস ফেরত দিতে পারে যা এই পদ্ধতির কোনওটির দ্বারা স্পর্শ হয়নি। উদাহরণস্বরূপ একক প্যাটার্নে এই পদ্ধতির গ্রহণ করুন:
class Meta_2(type):
singletons = {}
def __call__(cls, *args, **kwargs):
if cls in Meta_2.singletons:
# we return the only instance and skip a call to __new__()
# and __init__()
print ("{} singleton returning from Meta_2.__call__(), "
"skipping creation of new instance.".format(cls))
return Meta_2.singletons[cls]
# else if the singleton isn't present we proceed as usual
print "Meta_2.__call__() before creating an instance."
instance = super(Meta_2, cls).__call__(*args, **kwargs)
Meta_2.singletons[cls] = instance
print "Meta_2.__call__() returning new instance."
return instance
class Class_2(object):
__metaclass__ = Meta_2
def __new__(cls, *args, **kwargs):
print "Class_2.__new__() before creating instance."
instance = super(Class_2, cls).__new__(cls)
print "Class_2.__new__() returning instance."
return instance
def __init__(self, *args, **kwargs):
print "entering Class_2.__init__() for initialization."
super(Class_2, self).__init__()
print "exiting Class_2.__init__()."
বারবার টাইপের একটি অবজেক্ট তৈরি করার চেষ্টা করার পরে কী ঘটে তা পর্যালোচনা করা যাক Class_2
a = Class_2()
# Meta_2.__call__() before creating an instance.
# Class_2.__new__() before creating instance.
# Class_2.__new__() returning instance.
# entering Class_2.__init__() for initialization.
# exiting Class_2.__init__().
# Meta_2.__call__() returning new instance.
b = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.
c = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.
a is b is c # True
একটি মেটাক্লাস এমন একটি শ্রেণি যা বলে যে কীভাবে (কিছু) অন্যান্য শ্রেণি তৈরি করা উচিত।
এটি এমন একটি ক্ষেত্রে যেখানে আমি মেটাক্লাসকে আমার সমস্যার সমাধান হিসাবে দেখলাম: আমার একটি সত্যিই জটিল সমস্যা ছিল, সম্ভবত এটি অন্যরকমভাবে সমাধান করা যেতে পারে, তবে আমি এটি একটি মেটাক্লাস ব্যবহার করে সমাধান করার সিদ্ধান্ত নিয়েছি। জটিলতার কারণে, আমি লিখেছি এমন কয়েকটি মডিউলগুলির মধ্যে এটি একটি যেখানে মডিউলটিতে মন্তব্যগুলি কোডের পরিমাণের চেয়ে বেশি ছাড়িয়ে গেছে। এটা এখানে...
#!/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()
type(obj)
ফাংশন আপনি একটি বস্তুর টাইপ পায়।
type()
একটি বর্গ তার হয় ক্লাসের অধীনে একটি ক্লাস ।
একটি মেটাক্লাস ব্যবহার করতে:
class Foo(object):
__metaclass__ = MyMetaClass
type
এটি নিজস্ব মেটাক্লাস। শ্রেণীর শ্রেণি একটি metaclass - শ্রেণীর বডি হ'ল মেটাক্লাসে আর্গুমেন্টগুলি পাস করা হয় যা শ্রেণিটি নির্মাণে ব্যবহৃত হয়।
ক্লাস নির্মাণ কাস্টমাইজ করতে মেটাচ্লাসগুলি কীভাবে ব্যবহার করবেন সে সম্পর্কে এখানে আপনি পড়তে পারেন।
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
।
পাইথন ক্লাসগুলি তাদের মেটা-ক্লাসের - যেমন - উদাহরণস্বরূপ objects
ডিফল্ট মেটাক্লাস, যা প্রয়োগ করা হয় যখন যখন আপনি শ্রেণি নির্ধারণ করেন:
class foo:
...
ক্লাসের পুরো সেটটিতে কিছু নিয়ম প্রয়োগ করতে মেটা ক্লাস ব্যবহার করা হয়। উদাহরণস্বরূপ, ধরুন আপনি একটি ডাটাবেস অ্যাক্সেসের জন্য একটি ORM তৈরি করছেন এবং আপনি প্রতিটি টেবিলের রেকর্ডগুলি সেই টেবিলটিতে ম্যাপ করা শ্রেণীর হতে চান (ক্ষেত্র, ব্যবসায়ের নিয়ম, ইত্যাদি ..) ভিত্তিতে, মেটাক্লাসের সম্ভাব্য ব্যবহার উদাহরণস্বরূপ, সংযোগ পুল যুক্তি, যা সমস্ত সারণী থেকে রেকর্ডের সমস্ত শ্রেণীর দ্বারা ভাগ করা হয়। আর একটি ব্যবহার হ'ল বিদেশী কীগুলি সমর্থন করার জন্য যুক্তি, যাতে একাধিক শ্রেণীর রেকর্ড জড়িত।
আপনি যখন মেটাক্লাস সংজ্ঞায়িত করেন, আপনি সাবক্লাস টাইপ করেন এবং আপনার যুক্তি সন্নিবেশ করতে নিম্নলিখিত যাদু পদ্ধতিগুলিকে ওভাররাইড করতে পারেন।
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
যাইহোক, এই দুটি সবচেয়ে ব্যবহৃত হুক হয়। মেটাক্লাসিং শক্তিশালী, এবং উপরে মেটাক্লাসিংয়ের ব্যবহারের কাছাকাছি এবং বিস্তৃত তালিকা আর নেই।
টাইপ () ফাংশন কোনও অবজেক্টের ধরণ ফিরিয়ে দিতে বা একটি নতুন ধরণের তৈরি করতে পারে,
উদাহরণস্বরূপ, আমরা টাইপ () ফাংশন সহ একটি হাই ক্লাস তৈরি করতে পারি এবং হাই হাই (অবজেক্ট) সহ শ্রেণিটি এইভাবে ব্যবহার করার দরকার নেই:
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']
যখন আমরা মেটাক্লাসে কীওয়ার্ড আর্গুমেন্টগুলি পাস করি তখন ম্যাজিকটি কার্যকর হবে, এটি পাইথন ইন্টারপ্রেটারকে তালিকাম্যাটাক্লাসের মাধ্যমে কাস্টমলিস্ট তৈরি করতে ইঙ্গিত দেয়। নতুন (), এই মুহুর্তে, আমরা শ্রেণির সংজ্ঞাটি পরিবর্তন করতে পারি, উদাহরণস্বরূপ, এবং একটি নতুন পদ্ধতি যুক্ত করতে এবং তারপরে সংশোধিত সংজ্ঞাটি ফিরিয়ে আনতে পারি।
প্রকাশিত উত্তরগুলি ছাড়াও আমি বলতে পারি যে metaclass
কোনও শ্রেণীর জন্য আচরণকে সংজ্ঞায়িত করে। সুতরাং, আপনি স্পষ্টভাবে আপনার মেটাক্লাস সেট করতে পারেন। পাইথন যখনই কোনও কীওয়ার্ড পায় 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'
অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিংয়ে একটি মেটাক্লাস এমন একটি শ্রেণি যার উদাহরণগুলি বর্গ। একটি সাধারণ শ্রেণি যেমন কিছু নির্দিষ্ট জিনিসের আচরণকে সংজ্ঞায়িত করে, তেমনি একটি মেটাক্লাস নির্দিষ্ট শ্রেণীর আচরণ এবং তাদের দৃষ্টান্তগুলির সংজ্ঞা দেয় মেটাক্লাস শব্দের অর্থ ক্লাস তৈরির জন্য ব্যবহৃত কিছু। অন্য কথায়, এটি একটি শ্রেণীর শ্রেণি। ক্লাস তৈরির জন্য মেটাক্লাস ব্যবহার করা হয় যাতে বস্তু যেমন শ্রেণীর উদাহরণ, শ্রেণি একটি মেটাক্লাসের উদাহরণ। পাইথন ক্লাসেও বস্তু হিসাবে বিবেচিত হয়।
এটি কীসের জন্য ব্যবহার করা যেতে পারে তার আরেকটি উদাহরণ এখানে দেওয়া হয়েছে:
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
শক্তিশালী, সেখানে অনেক কিছু (যেমন বানর জাদু হিসাবে) আপনি এটি দিয়ে করতে পারেন, কিন্তু সতর্কতা অবলম্বন এটি শুধুমাত্র আপনার কাছে পরিচিত হতে পারে হতে হয়।
পাইথনের একটি শ্রেণি একটি অবজেক্ট এবং অন্য যে কোনও বস্তুর মতো এটিও "কিছু" উদাহরণস্বরূপ। এই "কিছু" কে মেটাক্লাস হিসাবে আখ্যায়িত করা হয়। এই মেটাক্লাস একটি বিশেষ ধরণের শ্রেণি যা অন্যান্য শ্রেণীর অবজেক্ট তৈরি করে। সুতরাং, নতুন ক্লাস তৈরির জন্য মেটাক্লাস দায়বদ্ধ is এটি প্রোগ্রামারকে ক্লাসগুলি উত্পন্ন করার পদ্ধতিটি কাস্টমাইজ করার অনুমতি দেয়।
একটি মেটাক্লাস তৈরি করতে, নতুন () এবং init () পদ্ধতির ওভাররাইডিং সাধারণত করা হয়। নতুন () অবজেক্ট তৈরি হওয়ার পদ্ধতি পরিবর্তন করতে ওভাররাইড করা যেতে পারে, যখন অবজেক্টের আরম্ভের পদ্ধতি পরিবর্তন করতে init () ওভাররাইড করা যায়। মেটাক্লাস বিভিন্ন উপায়ে তৈরি করা যেতে পারে। উপায়গুলির মধ্যে একটি হ'ল টাইপ () ফাংশন ব্যবহার করা। টাইপ () ফাংশন, যখন 3 টি প্যারামিটার সহ কল করা হয় তখন একটি মেটাক্লাস তৈরি করে। প্যারামিটারগুলি হ'ল: -
একটি মেটাক্লাস তৈরির অন্য উপায়টিতে 'মেটাক্লাস' কীওয়ার্ড রয়েছে। মেটাক্লাসকে একটি সাধারণ শ্রেণি হিসাবে সংজ্ঞায়িত করুন। উত্তরাধিকার সূত্রে প্রাপ্ত ক্লাসের প্যারামিটারে, মেটাক্লাস = মেটাগ্লাস_নাম পাস করুন
নিম্নলিখিত পরিস্থিতিতে মেটাক্লাস বিশেষভাবে ব্যবহার করা যেতে পারে: -
দ্রষ্টব্য যে অজগর 3.6 তে __init_subclass__(cls, **kwargs)
মেটাক্লাসগুলির প্রচুর প্রচলিত ব্যবহারের ক্ষেত্রে প্রতিস্থাপনের জন্য একটি নতুন ডান্ডার পদ্ধতি চালু করা হয়েছিল। যখন সংজ্ঞায়িত শ্রেণীর একটি সাবক্লাস তৈরি হয় তখন তাকে বলা হয়। পাইথন ডক্স দেখুন ।
মেটাক্লাস হ'ল এক ধরণের শ্রেণি যা ক্লাসটি কেমন আচরণ করবে তা নির্ধারণ করে বা আমরা বলতে পারি যে একটি শ্রেণি নিজেই একটি মেটাক্লাসের উদাহরণ।
class A(type):pass<NEWLINE>class B(type,metaclass=A):pass<NEWLINE>b.__class__ = b