Sök…


Ställa in ABCMeta-metaklass

Abstrakta klasser är klasser som är avsedda att ärva men undviker att implementera specifika metoder, vilket bara lämnar efter metodunderskrifter som underklasser måste implementera.

Abstrakta klasser är användbara för att definiera och upprätthålla klassabstraktioner på en hög nivå, liknande begreppet gränssnitt på typspråk, utan att det behövs metodimplementering.

Ett konceptuellt tillvägagångssätt för att definiera en abstrakt klass är att förhindra klassmetoderna och sedan höja en NotImplementedError om den finns tillgänglig. Detta förhindrar barnklasser från att få tillgång till överordnade metoder utan att åsidosätta dem först. Såhär:

class Fruit:
    
    def check_ripeness(self):
        raise NotImplementedError("check_ripeness method not implemented!")


class Apple(Fruit):
    pass


a = Apple()
a.check_ripeness() # raises NotImplementedError

Att skapa en abstrakt klass på detta sätt förhindrar felaktig användning av metoder som inte åsidosätts, och uppmuntrar verkligen metoder att definieras i barnklasser, men det verkställer inte deras definition. Med abc modulen kan vi förhindra att barnklasser blir instanserade när de inte åsidosätter abstrakta klassmetoder för sina föräldrar och förfäder:

from abc import ABCMeta

class AbstractClass(object):
    # the metaclass attribute must always be set as a class variable 
    __metaclass__ = ABCMeta

   # the abstractmethod decorator registers this method as undefined
   @abstractmethod 
   def virtual_method_subclasses_must_define(self):
       # Can be left completely blank, or a base implementation can be provided
       # Note that ordinarily a blank interpretation implicitly returns `None`, 
       # but by registering, this behaviour is no longer enforced.

Det är nu möjligt att helt enkelt underklassera och åsidosätta:

class Subclass(AbstractClass):
    def virtual_method_subclasses_must_define(self):
        return

Varför / hur man använder ABCMeta och @abstractmethod

Abstrakta basklasser (ABCs) verkställer vilka härledda klasser implementerar särskilda metoder från basklassen.

För att förstå hur detta fungerar och varför vi ska använda det, låt oss ta en titt på ett exempel som Van Rossum skulle tycka om. Låt oss säga att vi har en basklass "MontyPython" med två metoder (skämt & punchline) som måste implementeras av alla härledda klasser.

class MontyPython:
    def joke(self):
        raise NotImplementedError()

    def punchline(self):
        raise NotImplementedError()

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

När vi instanserar ett objekt och kallar det för två metoder får vi ett fel (som förväntat) med metoden punchline() .

 >>> sketch = ArgumentClinic() 
 >>> sketch.punchline() 
NotImplementedError 

Men det gör att vi fortfarande kan instansera ett objekt i klassen ArgumentClinic utan att få något fel. Vi får faktiskt inte ett fel förrän vi letar efter punchline ().

Detta undviks genom att använda modulen Abstract Base Class (ABC). Låt oss se hur detta fungerar med samma exempel:

from abc import ABCMeta, abstractmethod

class MontyPython(metaclass=ABCMeta):
    @abstractmethod
    def joke(self):
        pass

@abstractmethod
def punchline(self):
    pass

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

Den här gången när vi försöker instansera ett objekt från den ofullständiga klassen får vi omedelbart en TypeError!

>>> c = ArgumentClinic()
TypeError:
"Can't instantiate abstract class ArgumentClinic with abstract methods punchline"

I det här fallet är det enkelt att slutföra klassen för att undvika alla TypeErrors:

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

    def punchline(self):
        return "Send in the constable!"

Den här gången när du instanser ett objekt fungerar det!



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