Respostas:
O que você verá às vezes é o seguinte:
class Abstract1( object ):
"""Some description that tells you it's abstract,
often listing the methods you're expected to supply."""
def aMethod( self ):
raise NotImplementedError( "Should have implemented this" )
Como o Python não possui (e não precisa) um contrato formal de interface, a distinção no estilo Java entre abstração e interface não existe. Se alguém se esforçar para definir uma interface formal, também será uma classe abstrata. As únicas diferenças estariam na intenção declarada na doutrina.
E a diferença entre abstrato e interface é uma coisa complicada quando você digita pato.
Java usa interfaces porque não possui herança múltipla.
Como o Python tem herança múltipla, você também pode ver algo assim
class SomeAbstraction( object ):
pass # lots of stuff - but missing something
class Mixin1( object ):
def something( self ):
pass # one implementation
class Mixin2( object ):
def something( self ):
pass # another
class Concrete1( SomeAbstraction, Mixin1 ):
pass
class Concrete2( SomeAbstraction, Mixin2 ):
pass
Isso usa um tipo de superclasse abstrata com mixins para criar subclasses de concreto disjuntas.
NotImplementedError("Class %s doesn't implement aMethod()" % (self.__class__.__name__))
é a mensagem de erro mais informativa :)
Qual é a diferença entre classe abstrata e interface no Python?
Uma interface, para um objeto, é um conjunto de métodos e atributos nesse objeto.
No Python, podemos usar uma classe base abstrata para definir e aplicar uma interface.
Por exemplo, digamos que desejemos usar uma das classes base abstratas do collections
módulo:
import collections
class MySet(collections.Set):
pass
Se tentarmos usá-lo, obtemos um TypeError
porque a classe que criamos não suporta o comportamento esperado dos conjuntos:
>>> MySet()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__
Assim, somos obrigados a implementar pelo menos __contains__
, __iter__
e __len__
. Vamos usar este exemplo de implementação da documentação :
class ListBasedSet(collections.Set):
"""Alternate set implementation favoring space over speed
and not requiring the set elements to be hashable.
"""
def __init__(self, iterable):
self.elements = lst = []
for value in iterable:
if value not in lst:
lst.append(value)
def __iter__(self):
return iter(self.elements)
def __contains__(self, value):
return value in self.elements
def __len__(self):
return len(self.elements)
s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2
Podemos criar nossa própria classe base abstrata, definindo a metaclasse abc.ABCMeta
e usando o abc.abstractmethod
decorador nos métodos relevantes. A metaclasse adicionará as funções decoradas ao __abstractmethods__
atributo, impedindo a instanciação até que sejam definidas.
import abc
Por exemplo, "efável" é definido como algo que pode ser expresso em palavras. Digamos que desejamos definir uma classe base abstrata que seja eficaz, no Python 2:
class Effable(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def __str__(self):
raise NotImplementedError('users must define __str__ to use this base class')
Ou no Python 3, com a pequena alteração na declaração de metaclasse:
class Effable(object, metaclass=abc.ABCMeta):
@abc.abstractmethod
def __str__(self):
raise NotImplementedError('users must define __str__ to use this base class')
Agora, se tentarmos criar um objeto eficaz sem implementar a interface:
class MyEffable(Effable):
pass
e tente instancia-lo:
>>> MyEffable()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__
Dizem-nos que não terminamos o trabalho.
Agora, se cumprirmos, fornecendo a interface esperada:
class MyEffable(Effable):
def __str__(self):
return 'expressable!'
então podemos usar a versão concreta da classe derivada da abstrata:
>>> me = MyEffable()
>>> print(me)
expressable!
Há outras coisas que poderíamos fazer com isso, como registrar subclasses virtuais que já implementam essas interfaces, mas acho que isso está além do escopo desta questão. Os outros métodos demonstrados aqui teriam que adaptar esse método usando o abc
módulo para fazê-lo, no entanto.
Demonstramos que a criação de uma classe base abstrata define interfaces para objetos personalizados em Python.
Python> = 2.6 possui classes base abstratas .
As classes base abstratas (ABCs abreviadas) complementam a digitação de patos, fornecendo uma maneira de definir interfaces quando outras técnicas como hasattr () seriam desajeitadas. O Python vem com muitos ABCs internos para estruturas de dados (no módulo de coleções), números (no módulo de números) e fluxos (no módulo io). Você pode criar seu próprio ABC com o módulo abc.
Há também o módulo Zope Interface , que é usado por projetos fora do zope, como twisted. Eu não estou realmente familiarizado com isso, mas há uma página wiki aqui que pode ajudar.
Em geral, você não precisa do conceito de classes abstratas ou interfaces em python (editado - consulte a resposta de S.Lott para obter detalhes).
Python realmente não tem nenhum conceito.
Ele usa digitação de pato, o que eliminou a necessidade de interfaces (pelo menos para o computador :-))
Python <= 2.5: As classes base obviamente existem, mas não há uma maneira explícita de marcar um método como 'virtual puro'; portanto, a classe não é realmente abstrata.
Python> = 2.6: As classes base abstratas existem ( http://docs.python.org/library/abc.html ). E permita que você especifique métodos que devem ser implementados nas subclasses. Não gosto muito da sintaxe, mas o recurso está lá. Na maioria das vezes, provavelmente é melhor usar a digitação de pato no lado do cliente 'using'.
De uma maneira mais básica para explicar: Uma interface é como uma forma vazia de muffin. É um arquivo de classe com um conjunto de definições de métodos que não têm código.
Uma classe abstrata é a mesma coisa, mas nem todas as funções precisam estar vazias. Alguns podem ter código. Não é estritamente vazio.
Por que diferenciar: Não há muita diferença prática no Python, mas no nível de planejamento de um projeto grande, pode ser mais comum falar sobre interfaces, pois não há código. Especialmente se você estiver trabalhando com programadores Java acostumados ao termo.
Em geral, as interfaces são usadas apenas em idiomas que usam o modelo de classe de herança única. Nessas linguagens de herança única, as interfaces são normalmente usadas se alguma classe puder usar um método ou conjunto de métodos específico. Também nessas linguagens de herança única, as classes abstratas são usadas para ter variáveis de classe definidas, além de nenhum ou mais métodos, ou para explorar o modelo de herança única para limitar o intervalo de classes que poderia usar um conjunto de métodos.
Os idiomas que suportam o modelo de herança múltipla tendem a usar apenas classes ou classes base abstratas e não interfaces. Como o Python suporta herança múltipla, ele não usa interfaces e você deseja usar classes base ou classes base abstratas.
Classes abstratas são classes que contêm um ou mais métodos abstratos. Juntamente com os métodos abstratos, as classes Abstratas podem ter métodos estáticos, de classe e de instância. Mas no caso da interface, ela só terá métodos abstratos e não outros. Portanto, não é obrigatório herdar a classe abstrata, mas é obrigatório herdar a interface.
Por questões de integridade, devemos mencionar o PEP3119, onde o ABC foi introduzido e comparado com interfaces, e os originais de Talin. comentário .
A classe abstrata não é uma interface perfeita:
Mas se você pensar em escrever à sua maneira:
def some_function(self):
raise NotImplementedError()
interface = type(
'your_interface', (object,),
{'extra_func': some_function,
'__slots__': ['extra_func', ...]
...
'__instancecheck__': your_instance_checker,
'__subclasscheck__': your_subclass_checker
...
}
)
ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...
você perceberá rapidamente que está inventando a roda para finalmente alcançar
abc.ABCMeta
abc.ABCMeta
foi proposto como uma adição útil da funcionalidade de interface ausente, e isso é justo o suficiente em uma linguagem como python.
Certamente, ele foi aprimorado melhor enquanto escrevia a versão 3 e adicionava nova sintaxe e conceito de interface imutável ...
Conclusão:
The abc.ABCMeta IS "pythonic" interface in python