Zoeken…


De ABCMeta-metaclass instellen

Abstracte klassen zijn klassen die bedoeld zijn om te worden overgeërfd, maar vermijden de implementatie van specifieke methoden, waarbij alleen methode-handtekeningen achterblijven die subklassen moeten implementeren.

Abstracte klassen zijn nuttig voor het definiëren en afdwingen van klasse-abstracties op hoog niveau, vergelijkbaar met het concept van interfaces in getypte talen, zonder de noodzaak van methode-implementatie.

Een conceptuele benadering voor het definiëren van een abstracte klasse is om de klassemethoden te verwijderen en vervolgens een NotImplementedError op te roepen als deze wordt geopend. Dit voorkomt dat klassen van kinderen toegang krijgen tot oudermethoden zonder ze eerst te overschrijven. Zoals zo:

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


class Apple(Fruit):
    pass


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

Het creëren van een abstracte klasse op deze manier voorkomt oneigenlijk gebruik van methoden die niet worden opgeheven, en moedigt zeker methoden aan om te worden gedefinieerd in onderliggende klassen, maar het dwingt hun definitie niet af. Met de abc module kunnen we voorkomen dat kindklassen worden geïnstantieerd wanneer ze de abstracte klassenmethoden van hun ouders en voorouders niet overschrijven:

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.

Het is nu mogelijk om eenvoudig een subklasse te maken en te overschrijven:

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

Waarom / Hoe ABCMeta en @abstractmethod te gebruiken

Abstracte basisklassen (ABC's) dwingen welke afgeleide klassen bepaalde methoden van de basisklasse implementeren.

Om te begrijpen hoe dit werkt en waarom we het zouden moeten gebruiken, laten we een voorbeeld bekijken dat Van Rossum leuk zou vinden. Laten we zeggen dat we een basisklasse 'MontyPython' hebben met twee methoden (grap & punchline) die door alle afgeleide klassen moet worden geïmplementeerd.

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

    def punchline(self):
        raise NotImplementedError()

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

Wanneer we een object instantiëren en het twee methoden noemen, krijgen we een fout (zoals verwacht) met de methode punchline() .

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

Hierdoor kunnen we echter nog steeds een object van de klasse ArgumentClinic instantiëren zonder een fout te krijgen. We krijgen pas een foutmelding als we naar de punchline zoeken ().

Dit wordt vermeden door de ABC-module (Abstract Base Class) te gebruiken. Laten we eens kijken hoe dit werkt met hetzelfde voorbeeld:

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"

Dit keer wanneer we proberen een object uit de onvolledige klasse te instantiëren, krijgen we meteen een TypeError!

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

In dit geval is het eenvoudig om de klasse te voltooien om TypeErrors te voorkomen:

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

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

Dit keer wanneer u een object instantieert, werkt het!



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow