පයිතන්හි මෙටාක්ලාස් යනු කුමක්ද?


5722

පයිතන්හි, මෙටාක්ලාස් යනු කුමක්ද සහ අප ඒවා භාවිතා කරන්නේ කුමක් සඳහාද?

Answers:


2869

මෙටාක්ලාස් යනු පන්තියක පන්තියයි. පංතියක් පන්තියේ නිදසුනක් (එනම් වස්තුවක්) හැසිරෙන ආකාරය අර්ථ දක්වන අතර මෙටාක්ලාස් එකක් පන්තියක් හැසිරෙන ආකාරය අර්ථ දක්වයි. පංතියක් යනු මෙටාක්ලාස් එකක උදාහරණයකි.

පයිතන්හිදී ඔබට මෙටාක්ලාස් සඳහා අත්තනෝමතික ඇමතුම් භාවිතා කළ හැකිය ( ජෙරුබ් සංදර්ශන වැනි ), වඩා හොඳ ප්‍රවේශය නම් එය සත්‍ය පන්තියක් බවට පත් කිරීමයි. typeයනු පයිතන්හි සුපුරුදු මෙටාක්ලාස් ය. typeඑයම පන්තියක් වන අතර එය තමන්ගේම වර්ගයකි. ඔබට typeපයිතන් වැනි දෙයක් ප්‍රතිනිර්මාණය කිරීමට නොහැකි වනු ඇත , නමුත් පයිතන් ටිකක් වංචා කරයි. පයිතන් හි ඔබේම මෙටැක්ලාස් එකක් සෑදීමට ඔබට ඇත්ත වශයෙන්ම අවශ්‍ය වන්නේ උප පංතියයි type.

මෙටාක්ලාස් පන්ති කර්මාන්ත ශාලාවක් ලෙස බහුලව භාවිතා වේ. පංතිය ඇමතීමෙන් ඔබ වස්තුවක් නිර්මාණය කරන විට, පයිතන් මෙටාක්ලාස් ඇමතීමෙන් නව පන්තියක් (එය 'පන්තියේ ප්‍රකාශය ක්‍රියාත්මක කරන විට) නිර්මාණය කරයි. සාමාන්‍ය __init__හා __new__ක්‍රමවේදයන් සමඟ ඒකාබද්ධව , පංතියක් නිර්මාණය කිරීමේදී 'අමතර දේවල්' කිරීමට මෙටාක්ලාස් ඔබට ඉඩ සලසයි, එනම් නව පංතිය යම් ලේඛනයක් සමඟ ලියාපදිංචි කිරීම හෝ පන්තිය සම්පූර්ණයෙන්ම වෙනත් දෙයක් සමඟ ආදේශ කිරීම වැනි ය.

වූ විට classප්රකාශයක් ක්රියාත්මක වන, Python පළමු ශරීරය ඉටු classකේත සාමාන්ය වාරණ ප්රකාශයක් ලෙස. එහි ප්‍රති ing ලයක් ලෙස නාම අවකාශය (ආ ict ාවක්) පන්තියේ සිට පැවතිය යුතුය. මෙටාක්ලාස් තීරණය කරනු ලබන්නේ පංතියේ සිට (මෙටාක්ලාස් උරුම වී ඇත), __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__

13
class A(type):pass<NEWLINE>class B(type,metaclass=A):pass<NEWLINE>b.__class__ = b
pppery

20
ගම්මිරිස් ඔහු පැහැදිලිවම අදහස් කළේ ඔබට මෙටාක්ලාස් ලෙස ටයිප් භාවිතා නොකර වර්ගය ප්‍රතිනිර්මාණය කළ නොහැකි බවයි. කීමට තරම් සාධාරණයි.
හෝල් වෑන්

3
නිදර්ශන පන්තියේ නිදසුනක් ලෙස ලියාපදිංචි නොකිරීම () කැඳවිය යුතු නොවේද?
Ciasto piekarz

5
__metaclass__පයිතන් 3 හි සහය නොදක්වන සටහන . පයිතන් 3 භාවිතයේදී class MyObject(metaclass=MyType), python.org/dev/peps/pep-3115 සහ පහත පිළිතුර බලන්න.
බ්ලැක්ෂිෆ්ට්

2
ප්‍රලේඛනය මෙටාක්ලාස් තෝරාගත් ආකාරය විස්තර කරයි . මෙටාක්ලාස් ව්‍යුත්පන්න වී ඇති තරමට උරුම නොවේ. ඔබ මෙටාක්ලාස් එකක් නියම කරන්නේ නම්, එය එක් එක් මූලික පන්තියේ මෙටාක්ලාස් හි උප වර්ගයක් විය යුතුය; එසේ නොමැතිනම්, ඔබ භාවිතා කරන්නේ එකිනෙකාගේ මූලික පංතියේ මෙටැක්ලාස් වල උප ප්‍රභේදයක් වන මූලික පන්තියේ මෙටැක්ලාස් ය. එය හැකි බව සටහන කිසිදු වලංගු metaclass සොයා ගත හැකි, හා අර්ථ දැක්වීම අසාර්ථක වනු ඇත.
චෙප්නර්

6821

පන්ති වස්තු ලෙස

මෙටාක්ලාස් තේරුම් ගැනීමට පෙර, ඔබට පයිතන්හි පන්ති ප්‍රගුණ කළ යුතුය. ස්මාල්ටෝක් භාෂාවෙන් ණයට ගත් පන්ති යනු කුමක්ද යන්න පිළිබඳව පයිතන්ට ඉතා සුවිශේෂී අදහසක් ඇත.

බොහෝ භාෂාවල පන්ති යනු වස්තුවක් නිපදවන ආකාරය විස්තර කරන කේත කැබලි පමණි. පයිතන්හි ද එය සත්‍යයකි:

>>> class ObjectCreator(object):
...       pass
...

>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>

නමුත් පන්ති පයිතන් වලට වඩා වැඩිය. පන්ති යනු වස්තූන් ද වේ.

ඔව්, වස්තු.

ඔබ යතුරුපදය භාවිතා කළ විගස class, පයිතන් එය ක්‍රියාත්මක කර OBJECT එකක් නිර්මාණය කරයි. උපදෙස්

>>> class ObjectCreator(object):
...       pass
...

මතකයේ "ObjectCreator" නමින් වස්තුවක් නිර්මාණය කරයි.

මෙම වස්තුව (පංතිය) වස්තූන් (අවස්ථා) නිර්මාණය කිරීමේ හැකියාව ඇති අතර එය පන්තියක් වන්නේ එබැවිනි .

නමුත් තවමත්, එය වස්තුවකි, එබැවින්:

  • ඔබට එය විචල්‍යයකට පැවරිය හැකිය
  • ඔබට එය පිටපත් කළ හැකිය
  • ඔබට එයට ගුණාංග එකතු කළ හැකිය
  • ඔබට එය ක්‍රියාකාරී පරාමිතියක් ලෙස සම්මත කළ හැකිය

උදා:

>>> 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පන්තියක විස්තරය පරාමිතීන් ලෙස ගෙන පන්තියක් ආපසු ලබා දිය හැකිය.

(මම දනිමි, එකම ශ්‍රිතයට ඔබ ලබා දෙන පරාමිතීන් අනුව සම්පූර්ණයෙන්ම වෙනස් භාවිතයන් දෙකක් තිබිය හැකි බව මෝඩකමකි.

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>

අපි "MyShinyClass" පන්තියේ නම ලෙසත් පන්ති යොමු කිරීම සඳහා විචල්‍යය ලෙසත් භාවිතා කරන බව ඔබට පෙනෙනු ඇත. ඒවා වෙනස් විය හැකි නමුත් දේවල් සංකීර්ණ කිරීමට හේතුවක් නැත.

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__ගුණාංගය පරික්ෂා කිරීමෙන් ඔබට එය පෙනේ .

සෑම දෙයක්ම, සහ මම සියල්ලම අදහස් කළේ, පයිතන්හි වස්තුවකි. එයට ints, නූල්, ශ්‍රිත සහ පන්ති ඇතුළත් වේ. ඒවා සියල්ලම වස්තූන් ය. ඒවා සියල්ලම පන්තියකින් නිර්මාණය කර ඇත:

>>> 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__ගුණාංගයක් භාවිතා කරන්නේ නම් , උප පංතිවලට එම හැසිරීම උරුම නොවේ.Bartype()type.__new__()

දැන් විශාල ප්‍රශ්නය නම්, ඔබට කුමක් දැමිය __metaclass__හැකිද?

පිළිතුර: පන්තියක් නිර්මාණය කළ හැකි දෙයක්.

පංතියක් නිර්මාණය කළ හැක්කේ කුමක් ද? type, හෝ උප පංති හෝ භාවිතා කරන ඕනෑම දෙයක්.

පයිතන් 3 හි මෙටාක්ලාස්

මෙටාක්ලාස් සැකසීමේ වාක්‍ය ඛණ්ඩය පයිතන් 3 හි වෙනස් කර ඇත:

class Foo(object, metaclass=something):
    ...

එනම්, __metaclass__මූලික පංති ලැයිස්තුවේ මූල පද තර්කයකට පක්ෂව, ගුණාංගය තවදුරටත් භාවිතා නොවේ.

කෙසේ වෙතත් මෙටාක්ලාස් වල හැසිරීම බොහෝ දුරට සමාන වේ.

පයිතන් 3 හි මෙටාක්ලාස් වලට එකතු කරන ලද එක් දෙයක් නම්, ඔබට යතුරු පද-තර්ක ලෙස ගුණාංග මෙටාක්ලාස් වෙත යැවිය හැකිය.

class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
    ...

පයිතන් මෙය හසුරුවන ආකාරය සඳහා පහත කොටස කියවන්න.

අභිරුචි මෙටාක්ලාස්

මෙටාක්ලාස් එකක ප්‍රධාන අරමුණ වන්නේ පන්තිය නිර්මාණය වූ විට ස්වයංක්‍රීයව වෙනස් කිරීමයි.

ඔබ සාමාන්‍යයෙන් මෙය කරන්නේ API සඳහා වන අතර එහිදී ඔබට වර්තමාන සන්දර්භයට ගැලපෙන පන්ති නිර්මාණය කිරීමට අවශ්‍ය වේ.

මෝඩ උදාහරණයක් ගැන සිතන්න, එහිදී ඔබේ මොඩියුලයේ සියලුම පංතිවල ඉහළ අකුරින් ලියා තිබිය යුතු යැයි ඔබ තීරණය කරයි. මෙය කිරීමට ක්‍රම කිහිපයක් ඇත, නමුත් එක් ක්‍රමයක් වන්නේ __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පළමු පරාමිතිය, හෝ පන්ති ක්රම සඳහා නිර්වචනය පන්තියක් වශයෙන් උදාහරණයක් ලබා ඇති සාමාන්ය ක්රම සඳහා.

නමුත් මෙය නිසි OOP නොවේ. අපි 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):
        ...

ඒක තමයි. මෙටාක්ලාස් ගැන වැඩි යමක් නැත.

මෙටාක්ලාස් භාවිතා කරන කේතයේ සංකීර්ණතාවයට හේතුව මෙටාක්ලාස් නිසා නොවේ, එයට හේතුව ඔබ සාමාන්‍යයෙන් මෙටාක්ලාස් භාවිතා කරන්නේ ස්වයං විග්‍රහය, උරුමය හැසිරවීම __dict__, ආදී විවිධත්වය ආදිය මත රඳා පවතින විකෘති දේවල් කිරීමට ය .

ඇත්ත වශයෙන්ම, මෙටාක්ලාස් යනු මැජික් කිරීමට විශේෂයෙන් ප්රයෝජනවත් වන අතර එම නිසා සංකීර්ණ දේවල්. නමුත් ඔවුන් විසින්ම ඒවා සරල ය:

  • පන්ති නිර්මාණයක් බාධා කරන්න
  • පන්තිය වෙනස් කරන්න
  • වෙනස් කළ පන්තිය ආපසු එවන්න

කාර්යයන් වෙනුවට මෙටාක්ලාස් පන්ති භාවිතා කරන්නේ ඇයි?

සිට __metaclass__ඕනෑම callable පිළිගත හැකි, ඇයි ඔබ එය පැහැදිලිවම වැඩි සංකීර්ණ කිරීමේ සිට පන්ති භාවිතා කරන්නේ කෙසේද?

එසේ කිරීමට හේතු කිහිපයක් තිබේ:

  • අභිප්රාය පැහැදිලිය. ඔබ කියවන විට UpperAttrMetaclass(type), අනුගමනය කිරීමට යන්නේ කුමක්දැයි ඔබ දන්නවා
  • ඔබට OOP භාවිතා කළ හැකිය. මෙටාක්ලාස් වලට මෙටැක්ලාස් වලින් උරුම විය හැකිය, මව් ක්‍රම ඉක්මවා යන්න. මෙටාක්ලාස් වලට මෙටාක්ලාස් පවා භාවිතා කළ හැකිය.
  • ඔබ මෙටැක්ලාස් පංතියක් නියම කළහොත් පංතියක උප පංති එහි මෙටාක්ලාස් සඳහා උදාහරණ වනු ඇත, නමුත් මෙටැක්ලාස්-ශ්‍රිතයක් සමඟ නොවේ.
  • ඔබට ඔබේ කේතය වඩා හොඳින් සැකසිය හැකිය. ඉහත උදාහරණය තරම් සුළු දෙයක් සඳහා ඔබ කිසි විටෙක මෙටාක්ලාස් භාවිතා නොකරයි. එය සාමාන්‍යයෙන් සංකීර්ණ දෙයක් සඳහා ය. කේතය කියවීම පහසු කිරීම සඳහා ක්‍රම කිහිපයක් සැකසීමට සහ ඒවා එක් පන්තියකට කාණ්ඩගත කිරීමේ හැකියාව තිබීම ඉතා ප්‍රයෝජනවත් වේ.
  • ඔබට සම්බන්ධ විය හැකිය __new__, __init__සහ __call__. එමඟින් ඔබට විවිධ දේවල් කිරීමට ඉඩ ලබා දේ. සාමාන්‍යයෙන් ඔබට ඒ සියල්ල කළ හැකි වුවද __new__, සමහර පුද්ගලයින් භාවිතා කිරීම වඩාත් පහසුය __init__.
  • මේවා මෙටාක්ලාස් ලෙස හැඳින්වේ. එයින් යමක් අදහස් විය යුතුය!

ඔබ මෙටාක්ලාස් භාවිතා කරන්නේ ඇයි?

දැන් විශාල ප්‍රශ්නය. ඔබ කිසියම් අපැහැදිලි දෝෂ සහිත අංගයක් භාවිතා කරන්නේ ඇයි?

හොඳයි, සාමාන්‍යයෙන් ඔබ එසේ නොකරයි:

මෙටාක්ලාස් යනු 99% භාවිතා කරන්නන් කිසි විටෙකත් කරදර නොවිය යුතු ගැඹුරු මැජික් ය. ඔබට ඒවා අවශ්‍ය දැයි ඔබ සිතන්නේ නම්, ඔබට අවශ්‍ය නැත (ඇත්ත වශයෙන්ම ඔවුන්ට අවශ්‍ය පුද්ගලයින් ඔවුන්ට අවශ්‍ය බව නිසැකවම දනී, ඒ මන්ද යන්න පිළිබඳ පැහැදිලි කිරීමක් අවශ්‍ය නොවේ).

පයිතන් ගුරු ටිම් පීටර්ස්

මෙටාක්ලාස් සඳහා ප්‍රධාන භාවිත අවස්ථාව වන්නේ API නිර්මාණය කිරීමයි. මේ සඳහා සාමාන්‍ය උදාහරණයක් වන්නේ ජැන්ගෝ ඕආර්එම් ය. මේ වගේ දෙයක් අර්ථ දැක්වීමට එය ඔබට ඉඩ දෙයි:

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ඔබ සරල ප්‍රකාශයන් සමඟ අර්ථ දක්වා ඇති දත්ත සමුදා ක්ෂේත්‍රයට සංකීර්ණ කොක්කක් බවට පත් කරයි.

ජැන්ගෝ සරල API එකක් නිරාවරණය කිරීමෙන් හා මෙටාක්ලාස් භාවිතා කිරීමෙන් සංකීර්ණ දෙයක් සරල කරයි, තිරය පිටුපස සැබෑ කාර්යය කිරීමට මෙම API වෙතින් කේතය ප්‍රතිනිර්මාණය කරයි.

අන්තිම වචනය

පළමුව, පංති යනු නිදසුන් නිර්මාණය කළ හැකි වස්තු බව ඔබ දන්නවා.

ඇත්ත වශයෙන්ම, පන්ති යනු නිදසුන් ය. මෙටාක්ලාස් වලින්.

>>> class Foo(object): pass
>>> id(Foo)
142630324

සෑම දෙයක්ම පයිතන්හි වස්තුවක් වන අතර, ඒවා සියල්ලම පන්තිවල හෝ මෙටාක්ලාස් වල අවස්ථා වේ.

හැර type.

typeඇත්ත වශයෙන්ම එහි ම මෙටැක්ලාස් ය. මෙය ඔබට පිරිසිදු පයිතන් වලින් ප්‍රතිනිෂ්පාදනය කළ හැකි දෙයක් නොවන අතර එය ක්‍රියාත්මක කිරීමේ මට්ටමින් මඳක් වංචා කිරීමෙන් සිදු කෙරේ.

දෙවනුව, මෙටාක්ලාස් සංකීර්ණ වේ. ඉතා සරල පන්ති වෙනස් කිරීම් සඳහා ඒවා භාවිතා කිරීමට ඔබට අවශ්‍ය නොවනු ඇත. විවිධ ක්‍රම දෙකක් භාවිතා කිරීමෙන් ඔබට පන්ති වෙනස් කළ හැකිය:

ඔබට පන්ති වෙනස් කිරීම අවශ්‍ය වන කාලයෙන් 99% ක්ම මේවා භාවිතා කිරීමට වඩා හොඳය.

නමුත් 98% ක්ම ඔබට පන්ති වෙනස් කිරීමක් අවශ්‍ය නොවේ.


30
ජැන්ගෝ හි models.Modelඑය භාවිතා නොකරන __metaclass__නමුත් ඉහත සඳහන් කළ මෙටැක්ලාස් මැජික් class Model(metaclass=ModelBase):කරන ModelBaseපන්තියක් යොමු කිරීම බව පෙනේ . නියමයි! මෙන්න ජැන්ගෝ ප්‍රභවය: github.com/django/django/blob/master/django/db/models/…
මැක්ස් ගුඩ්රිජ්

15
<< මෙහිදී පරෙස්සම් වන්න, __metaclass__ගුණාංගය උරුම නොවන බවට, මවුපියන්ගේ ( Bar.__class__) මෙටාක්ලාස් එක වනු ඇත. (සහ නොවේ ) සමඟ සාදන Barලද __metaclass__ගුණාංගයක් භාවිතා කරන්නේ නම් , උප පංතිවලට එම හැසිරීම උරුම නොවනු ඇත. >> - ඔබට / යමෙකුට කරුණාකර මෙම කොටස ටිකක් ගැඹුරින් පැහැදිලි කළ හැකිද? Bartype()type.__new__()
petrux

15
Ax මැක්ස්ගුඩ්රිජ් යනු මෙටාක්ලාස් සඳහා වන පයිතන් 3 සින්ටැක්ස් ය. ශුද්ධාසනයේ Python 3.6 දත්ත ආකෘතිය VS Python 2.7 දත්ත ආකෘතිය
TBBle

2
Now you wonder why the heck is it written in lowercase, and not Type?- එය සී හි ක්‍රියාත්මක කර ඇති නිසා - පෙරනිමි නියෝගය කුඩා අකුරක් වන අතර ඕඩර්ඩෙක්ට් (පයිතන් 2 හි) සාමාන්‍ය
කැමල් කේස් වේ

15
එය ප්‍රජා විකී පිළිතුරකි (එබැවින්, නිවැරදි කිරීම් / වැඩිදියුණු කිරීම් සමඟ අදහස් දැක්වූ අය ඔවුන්ගේ අදහස් නිවැරදි යැයි විශ්වාස නම්, පිළිතුරට සංස්කරණය කිරීම සලකා බැලිය හැකිය).
බ්‍රැට්සෝර්ෆුස්ට්‍රොක්ස්

403

සටහන, මෙම පිළිතුර පයිතන් 2.x සඳහා 2008 දී ලියා ඇති පරිදි, මෙටාක්ලාස් 3.x හි තරමක් වෙනස් වේ.

මෙටැක්ලාස් යනු රහසිගත සෝස් ය. නව විලාසිතාවේ වස්තුවක් සඳහා පෙරනිමි මෙටැක්ලාස් 'වර්ගය' ලෙස හැඳින්වේ.

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

මෙටාක්ලාස් සඳහා ආර්ග් 3 ක් ගනී. ' name ', ' bases ' සහ ' dict '

රහස ආරම්භ වන ස්ථානය මෙන්න. මෙම උදාහරණ පන්ති අර්ථ දැක්වීමේදී නම, පදනම් සහ ආ ict ාව පැමිණෙන්නේ කොහෙන්දැයි සොයා බලන්න.

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

169

තවත් සමහරු මෙටාක්ලාස් ක්‍රියා කරන ආකාරය සහ ඒවා පයිතන් වර්ගයේ පද්ධතියට ගැලපෙන්නේ කෙසේද යන්න පැහැදිලි කර ඇත. මෙන්න ඒවා භාවිතා කළ හැකි දේ පිළිබඳ උදාහරණයක්. මා විසින් ලියන ලද පරීක්ෂණ රාමුවක, පන්ති නිර්වචනය කර ඇති අනුපිළිවෙල පිළිබඳව සොයා බැලීමට මට අවශ්‍ය විය, එවිට මට පසුව මෙම අනුපිළිවෙලෙහි ඒවා ක්ෂණිකව තහවුරු කර ගත හැකි විය. මෙටාක්ලාස් භාවිතයෙන් මෙය කිරීම පහසු බව මට පෙනී ගියේය.

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පංති අර්ථ දක්වා ඇති අනුපිළිවෙල සටහන් කරන පන්ති ලක්ෂණයක් ලැබේ .


උදාහරණයක් ලෙස ස්තූතියි. ඇයි ඔබ කාගේ MyBase, සිට උරුම වඩා මෙම පහසු සොයා ගත්තේ කෙසේද __init__(self)පවසයි type(self)._order = MyBase.counter; MyBase.counter += 1?
මයිකල් ගුන්ඩ්ලච්

1
මට අවශ්‍ය වූයේ පන්ති මිස ඔවුන්ගේ අවස්ථා නොවේ.
kindall

හරි, ඩු. ස්තූතියි. මගේ කේතය සෑම මොහොතකම MyType හි ගුණාංගය නැවත සකසනු ඇති අතර MyType හි නිදසුනක් කිසි විටෙකත් නිර්මාණය නොකළේ නම් එය කිසි විටෙකත් ගුණාංගය සැකසෙන්නේ නැත. අපොයි. (පංති දේපළකටද වැඩ කළ හැකි නමුත් මෙටාක්ලාස් මෙන් නොව එය කවුන්ටරය ගබඩා කිරීමට පැහැදිලි ස්ථානයක් සපයන්නේ නැත.)
මයිකල් ගුන්ඩ්ලච්

1
මෙය විහිළුවක් වන සිත්ගන්නාසුලු උදාහරණයකි, අවම වශයෙන් මෙටාක්ලාස් එකක් අවශ්‍ය නොවන්නේ මන්දැයි කෙනෙකුට අව්‍යාජව දැකිය හැකි නිසා, විශේෂිත දුෂ්කරතාවයකට විසඳුමක් ලබා දීම. OTOH ඕනෑම කෙනෙකුට ඔවුන්ගේ පංති නිර්වචනය කර ඇති අනුපිළිවෙලට වස්තූන් ක්ෂණිකව අවශ්‍ය බව ඒත්තු ගැන්වීමට මම වෙහෙසෙමි: මම හිතන්නේ අපි ඒ සඳහා ඔබේ වචනය ගත යුතුය :).
මයික් මීයන්

159

මෙටාක්ලාස් සඳහා එක් භාවිතයක් වන්නේ නිදසුනක් ලෙස නව ගුණාංග සහ ක්‍රම ස්වයංක්‍රීයව එකතු කිරීමයි.

උදාහරණයක් ලෙස, ඔබ ජැන්ගෝ ආකෘති දෙස බැලුවහොත්, ඒවායේ අර්ථ දැක්වීම ටිකක් අවුල් සහගතය. ඔබ පන්ති ගුණාංග පමණක් අර්ථ දක්වන බවක් පෙනේ:

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

කෙසේ වෙතත්, ධාවන වේලාවේදී පුද්ගල වස්තූන් සියලු ආකාරයේ ප්‍රයෝජනවත් ක්‍රම වලින් පුරවා ඇත. විස්මිත මෙටාක්ලාස්රි සඳහා මූලාශ්‍රය බලන්න .


6
මෙටා පන්ති භාවිතය සඳහා නව ගුණ හා ක්රම එකතු නොවේ පන්තියේ හා නොවන උදාහරණයක්? මා තේරුම් ගත් පරිදි මෙටා පන්තිය පන්තියම වෙනස් කරන අතර එහි ප්‍රති the ලයක් ලෙස වෙනස් වූ පන්තියට වෙනස් ආකාරයකින් ගොඩනැඟිය හැකිය. මෙටා පන්තියක ස්වභාවය ලබා ගැනීමට උත්සාහ කරන පුද්ගලයින්ට එය නොමඟ යවන සුළු විය හැකිය. අවස්ථා වලදී ප්‍රයෝජනවත් ක්‍රම තිබීම සාමාන්‍ය සහජයෙන්ම ලබා ගත හැකිය. නිදසුනක් ලෙස ජැන්ගෝ කේතය යොමු කිරීම හොඳයි.
ට්‍රික්ස්

119

මම සිතන්නේ මෙටැක්ලාස් ක්‍රමලේඛනය පිළිබඳ ඔන්ලෑම්ප් හැඳින්වීම හොඳින් ලියා ඇති අතර දැනටමත් වසර කිහිපයක් පැරණි වුවද මාතෘකාවට හොඳ හැඳින්වීමක් ලබා දෙයි.

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 )

කෙටියෙන් කිවහොත්: පංතියක් යනු නිදසුනක් නිර්මාණය කිරීම සඳහා වූ සැලැස්මක් වන අතර, මෙටාක්ලාස් යනු පංතියක් නිර්මාණය කිරීම සඳහා වූ සැලැස්මකි. මෙම හැසිරීම සක්‍රීය කිරීම සඳහා පයිතන් පංතිවල පළමු පන්තියේ වස්තු ද අවශ්‍ය බව පහසුවෙන් දැකිය හැකිය.

මම කවදාවත් තනිවම ලියා නැත, නමුත් මම සිතන්නේ මෙටාක්ලාස් වල ඇති හොඳම භාවිතයන්ගෙන් එකක් ජැන්ගෝ රාමුව තුළ දැකිය හැකිය . ආකෘති පංති නව ආකෘති ලිවීමේ හෝ ප්‍රකාශන පන්ති ප්‍රකාශ කිරීමේ ශෛලිය සක්‍රීය කිරීම සඳහා මෙටාක්ලාස් ප්‍රවේශයක් භාවිතා කරයි. මෙටාක්ලාස් පන්තිය නිර්මාණය කරන අතරම, සියලුම සාමාජිකයින්ට පන්තියම රිසිකරණය කිරීමේ හැකියාව ලැබේ.

කියන්න ඉතිරි වන බව දෙයක්: ඔබ metaclasses දේ දන්නේ නැහැ නම්, ඔබ සම්භාවිතාව ඔවුන් අවශ්ය වනු ඇත 99% ක් පමණ වේ.


109

මෙටාක්ලාස් යනු කුමක්ද? ඔබ ඒවා භාවිතා කරන්නේ කුමක් සඳහාද?

ටීඑල්ඩීආර්: මෙටාක්ලාස් එකක් පන්තියක් සඳහා හැසිරීම ක්ෂණිකව නිර්වචනය කරයි.

ව්‍යාජ කේතය:

>>> 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සුදුසු තර්ක සමඟ ක්‍රියාකාරීව කැඳවීම සහ එම නාමයේ විචල්‍යයකට ප්‍රති result ලය පැවරීම හා සමාන වේ:

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'})

මෙම metaclass අපි නිර්මාණය කළ වස්තුවක්, මේ අවස්ථා දෙකේ දී, වන 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__ ).

අපේක්ෂිත භාවිතය: __prepare__නාම අවකාශයක්

උදාහරණයක් ලෙස, පන්තියේ ක්‍රමවේදයන් නිර්මාණය කර ඇත්තේ කුමන අනුපිළිවෙලින් දැයි දැන ගැනීමට අපට අවශ්‍ය නම්, අපට පන්තියේ නාම අවකාශය ලෙස ඇණවුම් කළ නියෝගයක් ලබා දිය හැකිය. අප සමග මෙම කරන්නේ __prepare__කුමන එය Python 3 ක්රියාත්මක නම් පන්ති සඳහා නාම dict නැවත :

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>})

78

පයිතන් 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)

සරල උදාහරණයක්:

ඔබේ ගුණාංග මත ක්‍රියාත්මක වීමට සරල වලංගු කේතයක් අවශ්‍ය යැයි පවසන්න - එය සැමවිටම inta හෝ a විය strයුතුය. මෙටාක්ලාස් නොමැතිව, ඔබේ පන්තිය මෙවැනි දෙයක් වනු ඇත:

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

ඔබට පෙනෙන පරිදි, ඔබ ගුණාංගයේ නම දෙවරක් පුනරාවර්තනය කළ යුතුය. මෙමගින් කෝපාවිෂ් b දෝෂ සමඟ යතුරු ලියනය කළ හැකිය.

සරල මෙටාක්ලාස් එකකට එම ගැටළුව විසඳිය හැකිය:

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

වාව්, මෙය පයිතන් 3 හි පවතින බව මා නොදැන සිටි පුදුමාකාර නව අංගයකි. උදාහරණයට ස්තූතියි !!
පොහොසත් ලයිසකොව්ස්කි පීඑච්ඩී

පයිතන් 3.6 සිට, ඔබට __set_name__(cls, name)විස්තර කරන්නාගේ ( ValidateType) විස්තරයෙහි නම සැකසීමට භාවිතා කළ හැකි බව සලකන්න ( self.nameමේ අවස්ථාවේ දී ද self.attr). මෙම විශේෂිත පොදු භාවිත අවස්ථාව සඳහා මෙටාක්ලාස් වලට කිමිදීමට අවශ්‍ය නොවන ලෙස මෙය එකතු කරන ලදි (PEP 487 බලන්න).
ලාර්ස්

68

__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__()පංතියක නිදසුනක් කැඳවිය හැකි ලෙස භාවිතා කරන විට මෙම ක්‍රමය ක්‍රියාත්මක වේ. නමුත් පෙර පිළිතුරු වලින් අප දැක ඇති පරිදි පංතියක් යනු මෙටාක්ලාස් එකක නිදසුනකි, එබැවින් අපි පන්තිය කැඳවිය හැකි ලෙස භාවිතා කරන විට (එනම් අපි එය නිදසුනක් නිර්මාණය කරන විට) අපි ඇත්ත වශයෙන්ම එහි මෙටාක්ලාස් __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.

ඉහත කේතය ඇත්ත වශයෙන්ම කාර්යයන් ලොග් කිරීමට වඩා වැඩි යමක් නොකරන බව නිරීක්ෂණය කරන්න. සෑම ක්‍රමයක්ම මවුපියන්ගේ ක්‍රියාවට නැංවීම සඳහා සත්‍ය කාර්යය පවරයි. සිට typeMeta_1ගේ මව් පන්ති ( typeඅපි දැන් ව්යාජ ක්රියාත්මක වනු ඇත දේ ලෙස ඉඟියක් ඇති පෙරනිමි මව් metaclass වීම) සහ ඉහත නිමැවුම් ඇණවුම් අනුක්රමය සලකා, 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__() . එය අවසානයේ අවස්ථාව ලබා දෙන එක ද වේ.

එය ඉහත සිට metaclass 'බව කඳන් __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

මෙය කලින් ඉහළට ඔසවා ඇති "පිළිගත් පිළිතුරට" හොඳ එකතු කිරීමකි. එය අතරමැදි කෝඩර් හපන්නට උදාහරණ සපයයි.
පොහොසත් ලයිසකොව්ස්කි පීඑච්ඩී

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()

43

Tl; dr අනුවාදය

මෙම type(obj)ක්රියාව මඟින් ඔබට වස්තුවක වර්ගය වෙනවා.

මෙම type()පන්ති එහි වේ metaclass .

මෙටාක්ලාස් භාවිතා කිරීමට:

class Foo(object):
    __metaclass__ = MyMetaClass

typeඑහි ම මෙටැක්ලාස් ය. පංතියක පන්තිය මෙටාක්ලාස් එකක් - පංතියක ශරීරය යනු පංතිය තැනීම සඳහා භාවිතා කරන මෙටාක්ලාස් වෙත ඉදිරිපත් කරන තර්ක වේ.

මෙන්න ඔබ පන්තියේ ඉදිකිරීම් රිසිකරණය metaclasses භාවිතා කරන ආකාරය ගැන කියවන්න පුළුවන්.


42

typeඇත්ත වශයෙන්ම a 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.


27

පයිතන් පංති යනු ඔවුන්ගේ මෙටා පන්තියේ වස්තූන් ය.

පෙරනිමි මෙටාක්ලාස්, ඔබ පන්ති තීරණය කරන විට අදාළ වන්නේ:

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

කෙසේ වෙතත්, එම දෙක වඩාත් බහුලව භාවිතා වන කොකු වේ. metaclassing බලවත් වන අතර, ඉහත කොතැනකවත් ළඟා වී නැති අතර metaclassing සඳහා පරිපූර්ණ භාවිත ලැයිස්තුවක් ඇත.


21

වර්ගය () ශ්‍රිතයට වස්තුවක වර්ගය නැවත ලබා දිය හැකිය, නැතහොත් නව වර්ගයක් නිර්මාණය කළ හැකිය,

උදාහරණයක් ලෙස, අපට වර්ගය () ශ්‍රිතය සමඟ Hi පන්තියක් නිර්මාණය කළ හැකි අතර Hi (වස්තුව) පන්තිය සමඟ මේ ආකාරයෙන් භාවිතා කිරීම අවශ්‍ය නොවේ:

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']

අපි මෙටාක්ලාස් හි මූල පද තර්ක සම්මත කළ විට මැජික් ක්‍රියාත්මක වනු ඇත, එය ලැයිස්තු මෙටාක්ලාස් හරහා අභිරුචි ලැයිස්තුව නිර්මාණය කිරීම සඳහා පයිතන් පරිවර්තකය දක්වයි. නව (), මේ අවස්ථාවේදී, අපට පන්ති අර්ථ දැක්වීම වෙනස් කළ හැකිය, උදාහරණයක් ලෙස, නව ක්‍රමයක් එකතු කර සංශෝධිත අර්ථ දැක්වීම ආපසු එවන්න.


11

ප්‍රකාශිත පිළිතුරු වලට අමතරව 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'

4

වස්තු-නැඹුරු වැඩසටහන්කරණයේදී, මෙටාක්ලාස් යනු පන්ති වන අවස්ථා වේ. සාමාන්‍ය පංතියක් ඇතැම් වස්තූන්ගේ හැසිරීම නිර්වචනය කරනවා සේම, මෙටාක්ලාස් යනු යම් පන්තියක හැසිරීම සහ ඒවායේ අවස්ථා නිර්වචනය කරයි. වෙනත් වචන වලින් කිවහොත්, එය පන්තියක පන්තියයි. පංතිය නිර්මාණය කිරීම සඳහා මෙටාක්ලාස් භාවිතා කරනු ලැබේ, එම වස්තුව පන්තියක උදාහරණයක් ලෙස, පන්තියක් යනු මෙටාක්ලාස් එකක උදාහරණයකි. පයිතන් පංතිවල ද වස්තු ලෙස සැලකේ.


බුකිෂ් අර්ථ දැක්වීම් දෙනවා වෙනුවට, ඔබ උදාහරණ කිහිපයක් එකතු කළා නම් වඩා හොඳ වනු ඇත. ඔබගේ පිළිතුරේ පළමු පේළිය මෙටාක්ලාස් හි විකිපීඩියා පිවිසුමෙන් පිටපත් කර ඇති බව පෙනේ.
verisimilitude

ඔබේ අත්දැකීම් වලින් ප්‍රායෝගික උදාහරණ කිහිපයක් ලබා දීමෙන් මෙම පිළිතුර වැඩිදියුණු කිරීමට මට උදව් කළ හැකිද?
වෙනු ගෝපාල් තිවාරි

2

එය භාවිතා කළ හැකි දේ පිළිබඳ තවත් උදාහරණයක් මෙන්න:

  • 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බලවත් වන අතර, ඔබට එය කරන්න පුළුවන් බොහෝ දේ (එවැනි වඳුරු මැජික් ලෙස) ඇත, නමුත් එය, ඔබට දැන ගත හැක කල්පනාකාරී විය යුතුයි.


2

පයිතන්හි පන්තියක් යනු වස්තුවක් වන අතර වෙනත් ඕනෑම වස්තුවක් මෙන් එය “යමක්” පිළිබඳ නිදසුනකි. මෙම "යමක්" යනු මෙටැක්ලාස් ලෙස හැඳින්වේ. මෙම මෙටාක්ලාස් යනු වෙනත් පන්තියේ වස්තු නිර්මාණය කරන විශේෂ වර්ගයේ පන්තියකි. එබැවින් නව පංති සෑදීම සඳහා මෙටාක්ලාස් වගකීම දරයි. පංති ජනනය කරන ආකාරය රිසිකරණය කිරීමට මෙය ක්‍රමලේඛකයාට ඉඩ දෙයි.

මෙටාක්ලාස් එකක් සෑදීම සඳහා, නව () සහ init () ක්‍රම ඉක්මවා යාම සාමාන්‍යයෙන් සිදු කෙරේ. නව () වස්තූන් නිර්මාණය කරන ආකාරය වෙනස් කිරීම සඳහා අභිබවා යා හැකි අතර වස්තුව ආරම්භ කරන ආකාරය වෙනස් කිරීම සඳහා init () අභිබවා යා හැකිය. මෙටාක්ලාස් ක්‍රම කිහිපයකින් නිර්මාණය කළ හැකිය. එක් ක්‍රමයක් නම් වර්ගය () ශ්‍රිතය භාවිතා කිරීමයි. type () ශ්‍රිතය, පරාමිති 3 ක් සමඟ කැඳවූ විට, මෙටාක්ලාස් එකක් සාදයි. පරාමිතීන්: -

  1. පන්තියේ නම
  2. පංතියෙන් උරුම වූ මූලික පන්ති සහිත ටුපල්
  3. සියලුම පන්ති ක්‍රම සහ පන්ති විචල්‍යයන් සහිත ශබ්දකෝෂයක්

මෙටාක්ලාස් එකක් නිර්මාණය කිරීමේ තවත් ක්‍රමයක් වන්නේ 'මෙටැක්ලාස්' යතුරයි. මෙටාක්ලාස් සරල පන්තියක් ලෙස අර්ථ දක්වන්න. උරුම වූ පන්තියේ පරාමිතීන් තුළ, metaclass = metaclass_name පසු කරන්න

මෙටැක්ලාස් පහත සඳහන් අවස්ථාවන්හිදී විශේෂයෙන් භාවිතා කළ හැකිය: -

  1. සියලුම උප පංති සඳහා විශේෂිත බලපෑමක් යෙදිය යුතු විට
  2. පංතිය ස්වයංක්‍රීයව වෙනස් කිරීම (නිර්මාණය කිරීමේදී) අවශ්‍ය වේ
  3. API සංවර්ධකයින් විසින්

2

පයිතන් 3.6 හි මෙටාක්ලාස් __init_subclass__(cls, **kwargs)සඳහා පොදු භාවිත අවස්ථා රාශියක් ප්‍රතිස්ථාපනය කිරීම සඳහා නව ඩන්ඩර් ක්‍රමයක් හඳුන්වා දුන් බව සලකන්න . නිර්වචනය කරන පන්තියේ උප පංතියක් නිර්මාණය කරන විට එය හැඳින්වේ. පයිතන් ලියකියවිලි බලන්න .


-3

මෙටාක්ලාස් යනු පන්තියක් ලෙස හැසිරෙන ආකාරය නිර්වචනය කරන පන්තියකි. නැතහොත් පන්තියක් යනු මෙටාක්ලාස් එකක උදාහරණයක් යැයි අපට පැවසිය හැකිය.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.