É possível fazer classes abstratas em Python?

Como posso fazer uma classe ou método abstracto em Python?

tentei redefinir {[[2]} assim:

class F:
    def __new__(cls):
        raise Exception("Unable to create an instance of abstract class %s" %cls)
Mas agora se eu criar uma classe que herda de F assim:

class G(F):
    pass
Então também não posso instanciar, uma vez que chama ao método da super classe.

Há uma maneira melhor de definir uma classe abstrata?

Author: Martin Thoma, 2012-11-30

10 answers

abc módulo para criar classes abstratas. Use o abstractmethod decorador para declarar um método abstrato, e declarar uma classe abstrato usando uma de três maneiras, dependendo de sua versão Python.

Em Python 3.4 e acima, você pode herdar de ABC. Nas versões anteriores do Python, você precisa especificar o metaclass da sua classe como ABCMeta. A especificação do metaclass tem uma sintaxe diferente em Python 3 e Python 2. As três possibilidades são apresentados abaixo:

# Python 3.4+
from abc import ABC, abstractmethod
class Abstract(ABC):
    @abstractmethod
    def foo(self):
        pass
# Python 3.0+
from abc import ABCMeta, abstractmethod
class Abstract(metaclass=ABCMeta):
    @abstractmethod
    def foo(self):
        pass
# Python 2
from abc import ABCMeta, abstractmethod
class Abstract:
    __metaclass__ = ABCMeta

    @abstractmethod
    def foo(self):
        pass

Seja qual for a forma que use, não será capaz de instanciar uma classe abstracta que tenha métodos abstractos, mas será capaz de instanciar uma subclasse que forneça definições concretas desses métodos:

>>> Abstract()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Abstract with abstract methods foo
>>> class StillAbstract(Abstract):
...     pass
... 
>>> StillAbstract()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class StillAbstract with abstract methods foo
>>> class Concrete(Abstract):
...     def foo(self):
...         print('Hello, World')
... 
>>> Concrete()
<__main__.Concrete object at 0x7fc935d28898>
 366
Author: alexvassel, 2018-03-16 09:48:51

A maneira antiga (pré - PEP 3119 ) de fazer isto é apenas para raise NotImplementedError na classe abstracta quando um método abstracto é chamado.

class Abstract(object):
    def foo(self):
        raise NotImplementedError('subclasses must override foo()!')

class Derived(Abstract):
    def foo(self):
        print 'Hooray!'

>>> d = Derived()
>>> d.foo()
Hooray!
>>> a = Abstract()
>>> a.foo()
Traceback (most recent call last): [...]

Isto não tem as mesmas propriedades que usar o módulo abc. Você ainda pode instanciar a classe base abstrata em si, e você não vai encontrar o seu erro até que você chame o método abstrato em tempo de execução.

Mas se você está lidando com um pequeno conjunto de classes simples, talvez com apenas alguns métodos abstratos, esta abordagem é é mais fácil do que tentar ler a documentação.
 66
Author: Tim Gilbert, 2016-06-30 16:30:24

Este vai trabalhar no python 3

from abc import ABCMeta, abstractmethod

class Abstract(metaclass=ABCMeta):

    @abstractmethod
    def foo(self):
        pass

Abstract()
>>> TypeError: Can not instantiate abstract class Abstract with abstract methods foo
 8
Author: Rajkumar SR, 2017-11-07 05:59:21
Eis uma maneira muito fácil sem ter de lidar com o módulo ABC.

No método __init__ da classe que você quer ser uma classe abstrata, você pode verificar o "tipo" de si mesmo. Se o tipo de si mesmo é a classe base, então o chamador está tentando instanciar a classe base, então levantar uma exceção. Aqui está um exemplo simples:

class Base():
    def __init__(self):
        if type(self) is Base:
            raise Exception('Base is an abstract class and cannot be instantiated directly')
        # Any initialization code
        print('In the __init__  method of the Base class')

class Sub(Base):
    def __init__(self):
        print('In the __init__ method of the Sub class before calling __init__ of the Base class')
        super().__init__()
        print('In the __init__ method of the Sub class after calling __init__ of the Base class')

subObj = Sub()
baseObj = Base()

Quando executado, produz:

In the `__init__` method of the Sub class before calling `__init__` of the Base class

In the `__init__`  method of the Base class

In the `__init__` method of the Sub class after calling `__init__` of the Base class
Traceback (most recent call last):

  File "/Users/irvkalb/Desktop/Demo files/Abstract.py", line 16, in <module>
    baseObj = Base()

  File "/Users/irvkalb/Desktop/Demo files/Abstract.py", line 4, in `__init__`

    raise Exception('Base is an abstract class and cannot be instantiated directly')

Exception: Base is an abstract class and cannot be instantiated directly
Isto mostra que você pode instanciar uma subclasse que herda de uma classe base, mas você não pode instanciar a classe base diretamente.

Irv

 5
Author: Irv Kalb, 2018-01-16 05:37:16

A maioria das respostas anteriores estavam correctas, mas aqui está a resposta e o exemplo para o Python 3.7. Sim, você pode criar classe abstrata e método. Assim como um lembrete às vezes uma classe deve definir um método que logicamente pertence a uma classe, mas essa classe não pode especificar como implementar o método. Por exemplo, nas classes de pais e bebês abaixo que ambos comem, mas a implementação será diferente para cada um, porque bebês e pais comem diferentes tipos de alimentos e o número de vezes eles comem é diferente. Então, o método de comer em sub classes sobrepõe-se à AbstractClass.comer.

AbstractClass, come metho

import abc
from abc import ABC, abstractmethod
 class AbstractClass(ABC):

    def __init__(self, value):
        self.value = value
        super().__init__()

    @abstractmethod
    def eat(self):
        pass

class Parents(AbstractClass):
    def eat(self):
        return "eat solid food "+ str(self.value) + " times each day"

class Babies(AbstractClass):
    def eat(self):
        return "Milk only "+ str(self.value) + " times or more each day"

food = 3    
mom = Parents(food)
print("moms ----------")
print(mom.eat())

infant = Babies(food)
print("infants ----------")
print(infant.eat())

Resultado:

moms ----------
eat solid food 3 times each day
infants ----------
Milk only3 times or more each day
 2
Author: CPU 100, 2018-09-10 05:01:32

SIM, pode criar classes abstractas em python com o módulo abc (abstract base classes).

Este site vai ajudá-lo com ele: http://docs.python.org/2/library/abc.html

 1
Author: ORION, 2012-11-30 13:32:12

Isto também funciona e é simples:

class A_abstract(object):

    def __init__(self):
        # quite simple, old-school way.
        if self.__class__.__name__ == "A_abstract": 
            raise NotImplementedError("You can't instantiate this abstract class. Derive it, please.")

class B(A_abstract):

        pass

b = B()

# here an exception is raised:
a = A_abstract()
 1
Author: Giovanni Angeli, 2018-01-12 14:00:15

Sim você pode, usando o . abc - Módulo de Classes de base Abstractas, aqui está um exemplo:

Python3. 6

# importing abstract base classes module
import abc

class GetterSetter(abc.ABC):
    '''
    ABSTRACT BASE CLASSES:

    -  An abstract base class is a kind of 'model' for other classes to be defined.
        - It is not designed to construct instances, but can be subclassed by regular classes

    - Abstract classes can define interface, or methods that must be implemented by its subclasses.

    '''


    # Abstract classes are not designed to be instantiated, only to be subclassed

    #  decorator for abstract class
    @abc.abstractmethod
    def set_val(self, input):
        """set the value in the instance"""
        return

    @abc.abstractmethod
    def get_val(self):
        """Get and return a value from the instance..."""
        return

# Inheriting from the above abstract class
class MyClass(GetterSetter):

    # methods overriding in the GetterSetter
    def set_val(self, input):
        self.val = input

    def get_val(self):
        return self.val


# Instantiate
x = MyClass()
print(x) # prints the instance <__main__.MyClass object at 0x10218ee48>
x = GetterSetter() #throws error, abstract classes can't be instantiated

Python2.x

import abc

class GetterSetter(object):
    # meta class is used to define other classes
    __metaclass__ = abc.ABCMeta


    #  decorator for abstract class
    @abc.abstractmethod
    def set_val(self, input):
        """set the value in the instance"""
        return

    @abc.abstractmethod
    def get_val(self):
        """Get and return a value from the instance..."""
        return

# Inheriting from the above abstract class
class MyClass(GetterSetter):

    # methods overriding in the GetterSetter
    def set_val(self, input):
        self.val = input

    def get_val(self):
        return self.val


# Instantiate
x = GetterSetter()
print(x)
x = GetterSetter() #throws error, abstract classes can't be instantiated
 0
Author: rzskhr, 2017-11-04 15:36:25

No seu excerto de código, você também poderia resolver isso fornecendo uma implementação para o método __new__ na subclasse, da mesma forma:

def G(F):
    def __new__(cls):
        # do something here
Mas isto é uma invasão e aconselho-te a não o fazeres, a não ser que saibas o que estás a fazer. Para quase todos os casos eu aconselho você a usar o módulo abc, que outros antes de mim sugeriram.

Também quando você criar uma nova classe (base), faça-a subclasse object, Assim: class MyBaseClass(object):. Já não sei se é assim tão importante, mas ... ajuda a manter a consistência do estilo no seu código

 -1
Author: NlightNFotis, 2012-11-30 15:05:37
Apenas uma rápida adição à resposta da velha escola de @TimGilbert...você pode fazer com que o método init (da sua classe base abstrata) abra uma exceção e isso impediria que ela fosse instanciada, não?
>>> class Abstract(object):
...     def __init__(self):
...         raise NotImplementedError("You can't instantiate this class!")
...
>>> a = Abstract()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
NotImplementedError: You can't instantiate this class! 
 -1
Author: Dave Wade-Stein, 2017-08-07 23:10:04