457 Stimmen

Ist es möglich, abstrakte Klassen zu erstellen?

Wie kann ich eine Klasse oder Methode in Python abstrakt machen?

Ich habe versucht, eine neue Definition __new__() etwa so:

class F:
    def __new__(cls):
        raise Exception("Unable to create an instance of abstract class %s" %cls)

Aber wenn ich jetzt eine Klasse erstelle G die erbt von F etwa so:

class G(F):
    pass

Dann kann ich nicht instanziieren G auch nicht, denn sie ruft die Super-Klasse __new__ Methode.

Gibt es eine bessere Möglichkeit, eine abstrakte Klasse zu definieren?

3voto

Sie können eine abstrakte Klasse erstellen, indem Sie die ABC das steht für "Abstrakte Basisklassen" und kann die abstrakte Methode mit @Abstraktmethode in der abstrakten Klasse wie unten gezeigt:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass

Um eine abstrakte Klasse zu verwenden, sollte sie durch eine untergeordnete Klasse erweitert werden, und die untergeordnete Klasse sollte die abstrakte Methode der abstrakten Klasse außer Kraft setzen, wie unten gezeigt:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass

class Cat(Animal): # Extends "Animal" abstract class
    def sound(self): # Overrides "sound()" abstract method
        print("Meow!!")

obj = Cat()
obj.sound()

Ausgabe:

Meow!!

Und eine abstrakte Methode kann Code haben, anstatt pass und kann von einer untergeordneten Klasse wie unten gezeigt aufgerufen werden:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        print("Wow!!") # Here

class Cat(Animal):
    def sound(self):
        super().sound() # Here

obj = Cat()
obj.sound()

Ausgabe:

Wow!!

Und eine abstrakte Klasse kann Variablen und nicht-abstrakte Methoden haben, die von einer untergeordneten Klasse aufgerufen werden können, und nicht-abstrakte Methoden müssen nicht von einer untergeordneten Klasse überschrieben werden, wie unten gezeigt:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass

    def __init__(self): # Here
        self.name = "John" # Here

    x = "Hello" # Here

    def test1(self): # Here
        print("Test1")

    @classmethod # Here
    def test2(cls):
        print("Test2")

    @staticmethod # Here
    def test3():
        print("Test3")

class Cat(Animal):
    def sound(self):
        print(self.name) # Here
        print(super().x) # Here
        super().test1()  # Here
        super().test2()  # Here
        super().test3()  # Here

obj = Cat()
obj.sound()

Ausgabe:

John
Hello
Test1
Test2
Test3

Außerdem können Sie eine abstrakte Klasse und statische Methoden sowie einen abstrakten Getter, Setter und Deleter in einer abstrakten Klasse definieren, wie unten gezeigt. *@abstractmethod muss der innerste Dekorator sein, andernfalls tritt ein Fehler auf und Sie können sehen meine Antwort der mehr über abstrakte Getter, Setter und Deleter erklärt:

from abc import ABC, abstractmethod

class Person(ABC):

    @classmethod
    @abstractmethod # The innermost decorator
    def test1(cls):
        pass

    @staticmethod
    @abstractmethod # The innermost decorator
    def test2():
        pass

    @property
    @abstractmethod # The innermost decorator
    def name(self):
        pass

    @name.setter
    @abstractmethod # The innermost decorator
    def name(self, name):
        pass

    @name.deleter
    @abstractmethod # The innermost decorator
    def name(self):
        pass

Dann müssen Sie sie in einer untergeordneten Klasse überschreiben, wie unten gezeigt:

class Student(Person):

    def __init__(self, name):
        self._name = name

    @classmethod
    def test1(cls): # Overrides abstract class method
        print("Test1")

    @staticmethod
    def test2(): # Overrides abstract static method
        print("Test2")

    @property
    def name(self): # Overrides abstract getter
        return self._name

    @name.setter
    def name(self, name): # Overrides abstract setter
        self._name = name

    @name.deleter
    def name(self): # Overrides abstract deleter
        del self._name

Dann können Sie die untergeordnete Klasse instanziieren und sie wie unten gezeigt aufrufen:

obj = Student("John") # Instantiates "Student" class
obj.test1() # Class method
obj.test2() # Static method
print(obj.name) # Getter
obj.name = "Tom" # Setter
print(obj.name) # Getter
del obj.name # Deleter
print(hasattr(obj, "name"))

Ausgabe:

Test1
Test2
John 
Tom  
False

Und wenn Sie versuchen, eine abstrakte Klasse wie unten gezeigt zu instanziieren:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass

obj = Animal()

Der folgende Fehler tritt auf:

TypFehler: Kann die abstrakte Klasse Animal mit abstrakten Methoden nicht instanziieren sound

Und wenn Sie die abstrakte Methode einer abstrakten Klasse in einer untergeordneten Klasse nicht überschreiben und die untergeordnete Klasse wie unten gezeigt instanziieren:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass

class Cat(Animal):
    pass # Doesn't override "sound()" abstract method

obj = Cat() # Here

Der folgende Fehler tritt auf:

TypFehler: Kann die abstrakte Klasse Cat mit abstrakten Methoden nicht instanziieren sound

Und wenn Sie eine abstrakte Methode in einer nicht-abstrakten Klasse definieren, die keine Erweiterung von ABC Die abstrakte Methode ist eine normale Instanzmethode, so dass keine Fehler auftreten, selbst wenn die nicht-abstrakte Klasse instanziiert wird und selbst wenn eine untergeordnete Klasse die abstrakte Methode der nicht-abstrakten Klasse nicht überschreibt, wie unten gezeigt:

from abc import ABC, abstractmethod

class Animal: # Doesn't extend "ABC"
    @abstractmethod # Here
    def sound(self):
        print("Wow!!")

class Cat(Animal):
    pass # Doesn't override "sound()" abstract method

obj1 = Animal() # Here
obj1.sound()

obj2 = Cat() # Here
obj2.sound()

Ausgabe:

Wow!!
Wow!!

Darüber hinaus können Sie Folgendes ersetzen Cat Klasse Erweiterung Animal Klasse unten:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass

#  Here 

class Cat(Animal):
    def sound(self):
        print("Meow!!")

#  Here 

print(issubclass(Cat, Animal))

Mit diesem Code mit registrieren() unten:

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass

#  Here 

class Cat:
    def sound(self):
        print("Meow!!")

Animal.register(Cat)

#  Here 

print(issubclass(Cat, Animal))

Die beiden obigen Codes führen dann zu demselben Ergebnis, das unten angezeigt wird Cat Klasse ist die Unterklasse von Animal Klasse :

True

2voto

Drakes Punkte 21987

Ich bin zu spät dran, um hier zu antworten, aber um die andere Frage "Wie kann man abstrakt werden? Methoden ", die hierauf hinweisen, biete ich Folgendes an.

# decorators.py
def abstract(f):
    def _decorator(*_):
        raise NotImplementedError(f"Method '{f.__name__}' is abstract")
    return _decorator

# yourclass.py
class Vehicle:
    def add_energy():
       print("Energy added!")

    @abstract
    def get_make(): ...

    @abstract
    def get_model(): ...

Die Fahrzeug-Basisklasse kann immer noch für Unit-Tests instanziiert werden (anders als bei ABC), und das Pythonic-Auslösen einer Ausnahme ist vorhanden. Ach ja, Sie erhalten mit dieser Methode auch den Namen der Methode, die in der Ausnahme abstrakt ist.

-3voto

NlightNFotis Punkte 9471

In Ihrem Codeschnipsel könnten Sie das Problem auch lösen, indem Sie eine Implementierung für die __new__ Methode in der Unterklasse, ebenfalls:

def G(F):
    def __new__(cls):
        # do something here

Aber das ist ein Hack und ich rate Ihnen davon ab, es sei denn, Sie wissen, was Sie tun. Für fast alle Fälle rate ich Ihnen, die abc Modul, das andere vor mir vorgeschlagen haben.

Auch wenn Sie eine neue (Basis-)Klasse erstellen, machen Sie sie zur Unterklasse object etwa so: class MyBaseClass(object): . Ich weiß nicht, ob das noch von Bedeutung ist, aber es hilft, die Stilkonsistenz Ihres Codes zu erhalten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X