É 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?
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>
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.
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
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
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
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
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()
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
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
>>> 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!