Python Language
Metaclasses
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:
Ett speciellt __metaclass__
kan användas för att specificera metaklass.
class MyDummy(object):
__metaclass__ = mytype
type(MyDummy) # <class '__main__.mytype'>
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
class MySingleton(object):
__metaclass__ = SingletonType
class MySingleton(metaclass=SingletonType):
pass
MySingleton() is MySingleton() # True, only one instantiation occurs
Med hjälp av en metaklass
Metaclass-syntax
class MyClass(object):
__metaclass__ = SomeMetaclass
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.