Sök…


Introduktion

Metaclasses kan du djupt ändra beteendet hos Python klasser (i termer av hur de definieras, instansieras, nås med mera) genom att byta ut type meta att nya klasser användas som standard.

Anmärkningar

När du utformar din arkitektur bör du tänka på att många saker som kan utföras med metacglas också kan åstadkommas med hjälp av enklare semantik:

  • Traditionell arv är ofta mer än tillräckligt.
  • Klassdekoratörer kan blanda in funktionalitet i klasser i ad hoc-strategi.
  • Python 3.6 introducerar __init_subclass__() som tillåter en klass att delta i skapandet av sin underklass.

Grundläggande metaclasses

När type kallas med tre argument uppför den sig som den (metaklassen) den är, och skapar en ny instans, dvs. det producerar en ny klass / typ.

Dummy = type('OtherDummy', (), dict(x=1))
Dummy.__class__              # <type 'type'> 
Dummy().__class__.__class__  # <type 'type'> 

Det är möjligt att underklassa type att skapa ett anpassat metaklass.

class mytype(type):
    def __init__(cls, name, bases, dict):
        # call the base initializer
        type.__init__(cls, name, bases, dict)

        # perform custom initialization...
        cls.__custom_attribute__ = 2

Nu har vi ett nytt anpassat mytype metaklass som kan användas för att skapa klasser på samma sätt som type .

MyDummy = mytype('MyDummy', (), dict(x=2))
MyDummy.__class__              # <class '__main__.mytype'>
MyDummy().__class__.__class__  # <class '__main__.mytype'>
MyDummy.__custom_attribute__   # 2

När vi skapar en ny klass med hjälp av class nyckelordet metaklass är som standard väljas utifrån på de baseclasses.

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

>>> type(Foo)
type

I exemplet ovan är det enda basklasset object så vår metaklass kommer att vara typen av object , som är type . Det är möjligt att åsidosätta standarden, men det beror på om vi använder Python 2 eller Python 3:

Python 2.x 2.7

Ett speciellt __metaclass__ kan användas för att specificera metaklass.

class MyDummy(object):
    __metaclass__ = mytype
type(MyDummy)  # <class '__main__.mytype'>
Python 3.x 3.0

Ett speciellt metaclass anger metaklass.

class MyDummy(metaclass=mytype):
    pass
type(MyDummy)  # <class '__main__.mytype'>

Alla sökordsargument (utom metaclass ) i metaclass överförs till metaklass. Således kommer class MyDummy(metaclass=mytype, x=2) att skicka x=2 som ett nyckelordargument till mytype konstruktören.

Läs denna djupgående beskrivning av python-metaklasser för mer information.

Singletons med metaclasses

En singleton är ett mönster som begränsar inställningen av en klass till en instans / ett objekt. För mer info om python singleton designmönster, se här .

class SingletonType(type):
    def __call__(cls, *args, **kwargs):
        try:
            return cls.__instance
        except AttributeError:
            cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs)
            return cls.__instance
Python 2.x 2.7
class MySingleton(object):
    __metaclass__ = SingletonType
Python 3.x 3.0
class MySingleton(metaclass=SingletonType):
    pass
MySingleton() is MySingleton()  # True, only one instantiation occurs

Med hjälp av en metaklass

Metaclass-syntax

Python 2.x 2.7
class MyClass(object):
    __metaclass__ = SomeMetaclass
Python 3.x 3.0
class MyClass(metaclass=SomeMetaclass):
    pass

Python 2 och 3 kompatibilitet med six

import six

class MyClass(six.with_metaclass(SomeMetaclass)):
    pass

Anpassad funktionalitet med metaclasses

Funktionerna i metacglas kan ändras så att när en klass byggs skrivs ut en sträng till standardutmatning eller ett undantag kastas. Denna metaklass kommer att skriva ut namnet på klassen som byggs.

class VerboseMetaclass(type):

    def __new__(cls, class_name, class_parents, class_dict):
        print("Creating class ", class_name)
        new_class = super().__new__(cls, class_name, class_parents, class_dict)
        return new_class

Du kan använda metaclass så:

class Spam(metaclass=VerboseMetaclass):
    def eggs(self):
        print("[insert example string here]")
s = Spam()
s.eggs()

Standardutgången kommer att vara:

Creating class Spam
[insert example string here]

Introduktion till Metaclasses

Vad är ett metaklass?

I Python är allt ett objekt: heltal, strängar, listor, till och med funktioner och klasser är själva objekt. Och varje objekt är ett exempel på en klass.

För att kontrollera klassen för ett objekt x kan man ringa type(x) , så:

>>> type(5)
<type 'int'>
>>> type(str)
<type 'type'>
>>> type([1, 2, 3])
<type 'list'>

>>> class C(object):
...     pass
...
>>> type(C)
<type 'type'>    

De flesta klasser i python är exempel av type . type är också en klass. Sådana klasser vars instanser också är klasser kallas metaclasses.

Den enklaste metaclass

OK, så det finns redan en metaklass i Python: type . Kan vi skapa en annan?

class SimplestMetaclass(type):
    pass

class MyClass(object):
    __metaclass__ = SimplestMetaclass

Det lägger inte till någon funktion, men det är en ny metaklass, se att MyClass nu är ett exempel på SimplestMetaclass:

>>> type(MyClass)
<class '__main__.SimplestMetaclass'>

En metaclass som gör något

En metaklass som gör något vanligtvis åsidosätter type __new__ , för att ändra vissa egenskaper för klassen som ska skapas, innan du ringer till den ursprungliga __new__ som skapar klassen:

class AnotherMetaclass(type):
    def __new__(cls, name, parents, dct):
        # cls is this class
        # name is the name of the class to be created
        # parents is the list of the class's parent classes
        # dct is the list of class's attributes (methods, static variables)

        # here all of the attributes can be modified before creating the class, e.g.

        dct['x'] = 8  # now the class will have a static variable x = 8

        # return value is the new class. super will take care of that
        return super(AnotherMetaclass, cls).__new__(cls, name, parents, dct)

Standardmetaklass

Du kanske har hört att allt i Python är ett objekt. Det är sant, och alla objekt har en klass:

>>> type(1)
int

Den bokstavliga 1 är ett exempel på int . Låt oss förklara en klass:

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

Nu låter vi det:

>>> bar = Foo()

Vad är klassen i bar ?

>>> type(bar)
Foo

Trevligt, bar är ett exempel på Foo . Men vad är Foo klassen själv?

>>> type(Foo)
type

Okej, Foo själv är en type av type . Vad sägs om själva type ?

>>> type(type)
type

Så vad är ett metaklass? För nu låtsas att det bara är ett fint namn för klassens klass. takeaways:

  • Allt är ett objekt i Python, så allt har en klass
  • Klassens klass kallas ett metaklass
  • Standardmetaklass är type och det är överlägset det vanligaste metaklasset

Men varför ska du veta om metaclasses? Tja, Python själv är ganska "hackbar", och begreppet metaklass är viktigt om du gör avancerade saker som metaprogrammering eller om du vill kontrollera hur dina klasser initieras.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow