abc
— Abstrakta basklasser¶
Källkod: Lib/abc.py
Denna modul tillhandahåller infrastrukturen för att definiera abstract base classes (ABC) i Python, enligt PEP 3119; se PEP:en för varför detta lades till i Python. (Se även PEP 3141 och modulen numbers
angående en typhierarki för tal baserad på ABC)
Modulen collections
har några konkreta klasser som härstammar från ABC; dessa kan naturligtvis härledas ytterligare. Dessutom har undermodulen collections.abc
några ABC som kan användas för att testa om en klass eller instans tillhandahåller ett visst gränssnitt, t.ex. om den är hashable eller om den är en mapping.
Denna modul tillhandahåller metaklassen ABCMeta
för att definiera ABC och en hjälpklass ABC
för att alternativt definiera ABC genom arv:
- class abc.ABC¶
En hjälpklass som har
ABCMeta
som sin metaklass. Med denna klass kan en abstrakt basklass skapas genom att helt enkelt härleda frånABC
, vilket undviker ibland förvirrande användning av metaklasser, till exempel:från abc import ABC klass MyABC(ABC): pass
Observera att typen för
ABC
fortfarande ärABCMeta
, och att ärva frånABC
kräver därför de vanliga försiktighetsåtgärderna beträffande användning av metaklasser, eftersom flerfaldigt arv kan leda till metaklasskonflikter. Man kan också definiera en abstrakt basklass genom att skicka nyckelordet metaclass och användaABCMeta
direkt, till exempel:from abc import ABCMeta class MyABC(metaclass=ABCMeta): pass
Tillagd i version 3.4.
- class abc.ABCMeta¶
Metaklass för att definiera abstrakta basklasser (ABC).
Använd denna metaklass för att skapa en ABC. En ABC kan subklassas direkt och fungerar då som en mix-in klass. Du kan också registrera orelaterade konkreta klasser (även inbyggda klasser) och orelaterade ABC som ”virtuella underklasser” – dessa och deras ättlingar kommer att betraktas som underklasser till den registrerande ABC av den inbyggda
issubclass()
-funktionen, men den registrerande ABC kommer inte att dyka upp i deras MRO (Method Resolution Order) och inte heller kommer metodimplementationer som definieras av den registrerande ABC att kunna anropas (inte ens viasuper()
). [1]Klasser som skapats med en metaklass av
ABCMeta
har följande metod:- register(subclass)¶
Registrera subclass som en ”virtuell subclass” av denna ABC. Till exempel:
från abc import ABC klass MyABC(ABC): pass MyABC.register(tuple) assert issubclass(tuple, MyABC) assert isinstance((), MyABC)
Ändrad i version 3.3: Returnerar den registrerade subklassen, så att den kan användas som en klassdekorator.
Ändrad i version 3.4: För att upptäcka anrop till
register()
kan du använda funktionenget_cache_token()
.
Du kan också åsidosätta den här metoden i en abstrakt basklass:
- __subclasshook__(subclass)¶
(Måste definieras som en klassmetod.)
Kontrollera om subclass anses vara en subklass av denna ABC. Detta innebär att du kan anpassa beteendet hos
issubclass()
ytterligare utan att behöva anroparegister()
på varje klass du vill betrakta som en underklass till ABC. (Denna klassmetod anropas från ABC:s metod__subclasscheck__()
)Denna metod bör returnera
True
,False
ellerNotImplemented
. Om den returnerarTrue
, anses subclass vara en subklass av denna ABC. Om den returnerarFalse
anses subclass inte vara en subklass av denna ABC, även om den normalt skulle vara det. Om den returnerarNotImplemented
, fortsätter underklasskontrollen med den vanliga mekanismen.
För en demonstration av dessa begrepp, se detta exempel på ABC-definition:
klass Foo: def __getitem__(self, index): ... def __len__(self): ... def get_iterator(self): return iter(self) klass MyIterable(ABC): @abstraktmetod def __iter__(self): medan False: yield None def get_iterator(self): return self.__iter__() @klassmetod def __subclasshook__(cls, C): om cls är MyIterable: if any("__iter__" in B.__dict__ for B in C.__mro__): return True return Inte implementerad MyIterable.register(Foo)
ABC
MyIterable
definierar standardmetoden för iterable,__iter__()
, som en abstrakt metod. Den implementation som ges här kan fortfarande anropas från subklasser. Metodenget_iterator()
är också en del av den abstrakta basklassenMyIterable
, men den behöver inte åsidosättas i icke-abstrakta härledda klasser.Klassmetoden
__subclasshook__()
som definieras här säger att alla klasser som har en__iter__()
-metod i sin__dict__
(eller i en av dess basklasser, som nås via listan__mro__
) också betraktas som enMyIterable
.Slutligen, den sista raden gör
Foo
till en virtuell subklass avMyIterable
, även om den inte definierar en__iter__()
-metod (den använder det gamla iterabelprotokollet, definierat i termer av__len__()
och__getitem__()
). Observera att detta inte kommer att göraget_iterator
tillgänglig som en metod iFoo
, så den tillhandahålls separat.
Modulen abc
innehåller också följande dekorator:
- @abc.abstractmethod¶
En dekorator som anger abstrakta metoder.
För att använda denna dekorator krävs att klassens metaklass är
ABCMeta
eller är härledd från den. En klass som har en metaklass som härrör frånABCMeta
kan inte instansieras om inte alla dess abstrakta metoder och egenskaper åsidosätts. De abstrakta metoderna kan anropas med hjälp av någon av de normala ”super”-anropsmekanismerna.abstractmethod()
kan användas för att deklarera abstrakta metoder för egenskaper och deskriptorer.Att dynamiskt lägga till abstrakta metoder i en klass, eller att försöka ändra abstraktionsstatusen för en metod eller klass när den väl har skapats, stöds endast med funktionen
update_abstractmethods()
. Funktionenabstractmethod()
påverkar endast underklasser som härletts med hjälp av vanligt arv; ”virtuella underklasser” som registrerats med ABC:s metodregister()
påverkas inte.När
abstractmethod()
används i kombination med andra metodbeskrivare bör den användas som den innersta dekoratorn, vilket visas i följande användningsexempel:klass C(ABC): @abstraktmetod def my_abstract_method(self, arg1): ... @klassmetod @abstraktmetod def my_abstract_classmethod(cls, arg2): ... @statiskmetod @abstraktmetod def my_abstract_staticmethod(arg3): ... @egenskap @abstraktmetod def my_abstract_property(self): ... @my_abstract_property.setter @abstraktmetod def my_abstract_property(self, val): ... @abstraktmetod def _get_x(self): ... @abstraktmetod def _set_x(self, val): ... x = property(_get_x, _set_x)
För att korrekt kunna samverka med den abstrakta basklassens maskineri måste deskriptorn identifiera sig själv som abstrakt med hjälp av
__isabstractmethod__
. I allmänhet bör detta attribut varaTrue
om någon av de metoder som används för att komponera deskriptorn är abstrakt. Till exempel gör Pythons inbyggdaproperty
motsvarande:klassen Descriptor: ... @egenskap def __isabstractmethod__(self): return any(getattr(f, '__isabstractmethod__', False) for f in (self._fget, self._fset, self._fdel))
Anteckning
Till skillnad från Javas abstrakta metoder kan dessa abstrakta metoder ha en implementation. Denna implementation kan anropas via
super()
-mekanismen från den klass som åsidosätter den. Detta kan vara användbart som en slutpunkt för ett superanrop i ett ramverk som använder kooperativ multipel nedärvning.
Modulen abc
har även stöd för följande äldre dekoratorer:
- @abc.abstractclassmethod¶
Tillagd i version 3.2.
Föråldrad sedan version 3.3: Det är nu möjligt att använda
classmethod
medabstractmethod()
, vilket gör denna dekorator överflödig.En subklass av den inbyggda
classmethod()
, vilket indikerar en abstrakt klassmetod. Annars liknar denabstractmethod()
.Detta specialfall är inte längre aktuellt, eftersom
classmethod()
-dekoratorn nu identifieras korrekt som abstrakt när den tillämpas på en abstrakt metod:klass C(ABC): @klassmetod @abstraktmetod def my_abstract_classmethod(cls, arg): ...
- @abc.abstractstaticmethod¶
Tillagd i version 3.2.
Föråldrad sedan version 3.3: Det är nu möjligt att använda
staticmethod
medabstractmethod()
, vilket gör denna dekorator överflödig.En subklass av den inbyggda
staticmethod()
, vilket indikerar en abstrakt staticmethod. Annars liknar denabstractmethod()
.Detta specialfall är inte längre aktuellt, eftersom
staticmethod()
-dekoratorn nu identifieras korrekt som abstrakt när den tillämpas på en abstrakt metod:klass C(ABC): @statiskmetod @abstraktmetod def my_abstract_staticmethod(arg): ...
- @abc.abstractproperty¶
Föråldrad sedan version 3.3: Det är nu möjligt att använda
property
,property.getter()
,property.setter()
ochproperty.deleter()
medabstractmethod()
, vilket gör denna dekorator överflödig.En subklass av den inbyggda
property()
, som anger en abstrakt egenskap.Detta specialfall är inte längre aktuellt, eftersom
property()
-dekoratorn nu identifieras korrekt som abstrakt när den tillämpas på en abstrakt metod:klass C(ABC): @egenskap @abstraktmetod def my_abstract_property(self): ...
I exemplet ovan definieras en skrivskyddad egenskap; du kan också definiera en abstrakt skrivskyddad egenskap genom att på lämpligt sätt markera en eller flera av de underliggande metoderna som abstrakt:
klass C(ABC): @egenskap def x(self): ... @x.setter @abstraktmetod def x(self, val): ...
Om endast vissa komponenter är abstrakta, behöver endast dessa komponenter uppdateras för att skapa en konkret egenskap i en underklass:
klass D(C): @C.x.setter def x(self, val): ...
Modulen abc
innehåller även följande funktioner:
- abc.get_cache_token()¶
Returnerar den aktuella cachetoken för abstrakta basklasser.
Token är ett opakt objekt (som stöder likhetstestning) som identifierar den aktuella versionen av den abstrakta basklassens cache för virtuella underklasser. Token ändras med varje anrop till
ABCMeta.register()
på valfri ABC.Tillagd i version 3.4.
- abc.update_abstractmethods(cls)¶
En funktion för att räkna om en abstrakt klass abstraktionsstatus. Denna funktion bör anropas om en klass abstrakta metoder har implementerats eller ändrats efter att den skapades. Vanligtvis bör denna funktion anropas inifrån en klassdekorator.
Returnerar cls, så att den kan användas som en klassdekorator.
Om cls inte är en instans av
ABCMeta
, gör ingenting.Anteckning
Denna funktion förutsätter att clss superklasser redan är uppdaterade. Den uppdaterar inte några underklasser.
Tillagd i version 3.10.
Fotnoter