Um mixin é um tipo especial de herança múltipla. Existem duas situações principais em que os mixins são usados:
- Você deseja fornecer muitos recursos opcionais para uma classe.
- Você deseja usar um recurso específico em várias classes diferentes.
Para um exemplo do número um, considere o sistema de solicitação e resposta do werkzeug . Eu posso criar um objeto de solicitação antigo simples dizendo:
from werkzeug import BaseRequest
class Request(BaseRequest):
pass
Se eu quiser adicionar suporte ao cabeçalho Accept, eu faria isso
from werkzeug import BaseRequest, AcceptMixin
class Request(AcceptMixin, BaseRequest):
pass
Se eu quisesse fazer um objeto de solicitação que suporte aceitar cabeçalhos, etags, autenticação e suporte ao agente do usuário, eu poderia fazer o seguinte:
from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin
class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
pass
A diferença é sutil, mas nos exemplos acima, as classes de mixin não foram criadas por conta própria. Na herança múltipla mais tradicional, o AuthenticationMixin
(por exemplo) provavelmente seria algo mais parecido Authenticator
. Ou seja, a classe provavelmente seria projetada para se sustentar por conta própria.
Parent
classe eChild1
,Child2
,ChildN
subclasses dentro de uma biblioteca parte 3, e você quer um comportamento personalizado para toda a família. Idealmente, você gostaria de adicionar esse comportamentoParent
e espero que o desenvolvedor da biblioteca de terceiros aceite sua solicitação de recebimento. Caso contrário, você terá que implementar seu próprioclass NewBehaviorMixin
e, em seguida, definir um conjunto completo de classes de mensagens publicitárias, comoclass NewParent(NewBehaviorMixin, Parent): pass
eclass NewChildN(NewBehaviorMixin, ChildN): pass
, etc.: (PS Você conhece uma maneira melhor?)Primeiro, você deve observar que os mixins existem apenas em idiomas de herança múltipla. Você não pode fazer um mixin em Java ou C #.
Basicamente, um mixin é um tipo de base independente que fornece funcionalidade limitada e ressonância polimórfica para uma classe filho. Se você está pensando em C #, pense em uma interface que você não precisa implementar porque ela já está implementada; você apenas herda e se beneficia de sua funcionalidade.
Mixins são tipicamente de escopo estreito e não devem ser estendidos.
[editar - por que:]
Suponho que devo abordar o porquê, desde que você perguntou. O grande benefício é que você não precisa fazer isso sozinho uma e outra vez. Em C #, o maior local em que um mixin poderia se beneficiar pode ser o padrão de Disposição . Sempre que você implementa o IDisposable, quase sempre deseja seguir o mesmo padrão, mas acaba escrevendo e reescrevendo o mesmo código básico com pequenas variações. Se houver uma mixagem descartável extensível, você poderá economizar bastante digitação extra.
[editar 2 - para responder suas outras perguntas]
Sim. A diferença entre uma mistura e herança múltipla padrão é apenas uma questão de semântica; uma classe que tem herança múltipla pode utilizar um mixin como parte dessa herança múltipla.
O objetivo de um mixin é criar um tipo que possa ser "misturado" a qualquer outro tipo por herança, sem afetar o tipo de herança e ainda oferecer algumas funcionalidades benéficas para esse tipo.
Mais uma vez, pense em uma interface que já esteja implementada.
Pessoalmente, não uso mixins, já que desenvolvo principalmente em uma linguagem que não os suporta, por isso estou tendo dificuldades para encontrar um exemplo decente que apenas forneça esse "ahah!" momento para você. Mas vou tentar novamente. Vou usar um exemplo que é artificial - a maioria das linguagens já fornece o recurso de uma maneira ou de outra -, mas espero que explique como os mixins devem ser criados e usados. Aqui vai:
Suponha que você tenha um tipo que deseja poder serializar de e para XML. Você deseja que o tipo forneça um método "ToXML" que retorne uma sequência contendo um fragmento XML com os valores de dados do tipo e um "FromXML" que permita ao tipo reconstruir seus valores de dados a partir de um fragmento XML em uma sequência. Novamente, este é um exemplo artificial, então talvez você use um fluxo de arquivos ou uma classe XML Writer da biblioteca de tempo de execução da sua linguagem ... qualquer que seja. O ponto é que você deseja serializar seu objeto para XML e obter um novo objeto de volta a partir de XML.
O outro ponto importante neste exemplo é que você deseja fazer isso de maneira genérica. Você não precisa implementar os métodos "ToXML" e "FromXML" para todos os tipos que deseja serializar; deseja alguns meios genéricos de garantir que seu tipo faça isso e funcione. Você deseja reutilizar o código.
Se o seu idioma o suportasse, você poderia criar o mixin XmlSerializable para fazer seu trabalho. Esse tipo implementaria os métodos ToXML e FromXML. Seria, usando algum mecanismo que não é importante para o exemplo, ser capaz de reunir todos os dados necessários de qualquer tipo com o qual é misturado para criar o fragmento XML retornado pelo ToXML e seria igualmente capaz de restaurar esses dados quando o FromXML for chamado.
E é isso. Para usá-lo, você teria qualquer tipo que precise ser serializado para XML herdado de XmlSerializable. Sempre que você precisar serializar ou desserializar esse tipo, basta chamar ToXML ou FromXML. De fato, como XmlSerializable é um tipo completo e polimórfico, é possível criar um serializador de documentos que não saiba nada sobre o seu tipo original, aceitando apenas, digamos, uma matriz de tipos XmlSerializable.
Agora imagine usar esse cenário para outras coisas, como criar um mixin que garanta que toda classe que o mescla registre todas as chamadas de método ou um mixin que forneça transacionalidade para o tipo que o mescla. A lista pode continuar.
Se você apenas pensa em um mixin como um pequeno tipo de base, projetado para adicionar uma pequena quantidade de funcionalidade a um tipo sem afetar esse tipo, então você é dourado.
Esperançosamente. :)
fonte
Esta resposta tem como objetivo explicar os mixins com exemplos que são:
independente : curto, sem a necessidade de conhecer nenhuma biblioteca para entender o exemplo.
em Python , não em outros idiomas.
É compreensível que houvesse exemplos de outras linguagens, como Ruby, já que o termo é muito mais comum nessas linguagens, mas esse é um encadeamento Python .
Também deve considerar a questão controversa:
Definições
Ainda não vi uma citação de uma fonte "autorizada" dizendo claramente o que é um mixin no Python.
Eu já vi duas definições possíveis de um mixin (se elas devem ser consideradas diferentes de outros conceitos semelhantes, como classes básicas abstratas), e as pessoas não concordam inteiramente sobre qual delas está correta.
O consenso pode variar entre diferentes idiomas.
Definição 1: nenhuma herança múltipla
Um mixin é uma classe de tal forma que algum método da classe usa um método que não está definido na classe.
Portanto, a classe não deve ser instanciada, mas serve como uma classe base. Caso contrário, a instância teria métodos que não podem ser chamados sem gerar uma exceção.
Uma restrição que algumas fontes adicionam é que a classe pode não conter dados, apenas métodos, mas não vejo por que isso é necessário. Na prática, no entanto, muitos mixins úteis não possuem dados e as classes base sem dados são mais simples de usar.
Um exemplo clássico é a implementação de todos os operadores de comparação apenas
<=
e==
:Este exemplo em particular poderia ter sido alcançado através do
functools.total_ordering()
decorador, mas o jogo aqui era reinventar a roda:Definição 2: herança múltipla
Um mixin é um padrão de design no qual algum método de uma classe base usa um método que não define, e esse método deve ser implementado por outra classe base , não pelo derivado, como na Definição 1.
O termo classe mixin refere-se a classes base que devem ser usadas nesse padrão de design (TODO aquelas que usam o método ou aquelas que o implementam?)
Não é fácil decidir se uma determinada classe é uma combinação ou não: o método pode ser implementado apenas na classe derivada; nesse caso, voltamos à definição 1. Você deve considerar as intenções do autor.
Esse padrão é interessante porque é possível recombinar funcionalidades com diferentes opções de classes base:
Ocorrências oficiais do Python
Na documentação oficial para coleções.abc, a documentação usa explicitamente o termo Métodos Mixin .
Ele afirma que se uma classe:
__next__
Iterator
então a classe recebe um
__iter__
método mixin de graça.Portanto, pelo menos neste ponto da documentação, mixin não requer herança múltipla e é coerente com a Definição 1.
É claro que a documentação pode ser contraditória em pontos diferentes, e outras bibliotecas Python importantes podem estar usando a outra definição em sua documentação.
Esta página também usa o termo
Set mixin
, que sugere claramente que as classes gostamSet
eIterator
podem ser chamadas de classes Mixin.Em outros idiomas
Ruby: Claramente não requer herança múltipla para mixin, como mencionado nos principais livros de referência, como Programming Ruby e The Ruby programming Language
C ++: um método que não é implementado é um método virtual puro.
A definição 1 coincide com a definição de uma classe abstrata (uma classe que possui um método virtual puro). Essa classe não pode ser instanciada.
A definição 2 é possível com herança virtual: herança múltipla de duas classes derivadas
fonte
Penso neles como uma maneira disciplinada de usar herança múltipla - porque, em última análise, um mixin é apenas outra classe python que (pode) seguir as convenções sobre classes chamadas mixins.
Meu entendimento das convenções que governam algo que você chamaria de Mixin é que um Mixin:
object
(em Python)Dessa forma, limita a complexidade potencial da herança múltipla e facilita razoavelmente o rastreamento do fluxo do seu programa, limitando para onde você deve procurar (em comparação com a herança múltipla completa). Eles são semelhantes aos módulos ruby .
Se eu quiser adicionar variáveis de instância (com mais flexibilidade do que o permitido por herança única), então tendem a procurar composição.
Dito isto, vi classes chamadas XYZMixin que possuem variáveis de instância.
fonte
Mixins é um conceito em Programação no qual a classe fornece funcionalidades, mas não deve ser usada para instanciação. O principal objetivo do Mixins é fornecer funcionalidades independentes e seria melhor se os próprios mixins não tivessem herança com outros mixins e também evitassem o estado. Em linguagens como Ruby, existe algum suporte direto à linguagem, mas para Python, não existe. No entanto, você pode usar a herança de várias classes para executar a funcionalidade fornecida no Python.
Eu assisti esse vídeo http://www.youtube.com/watch?v=v_uKI2NOLEM para entender o básico dos mixins. É bastante útil para um iniciante entender os conceitos básicos de mixins e como eles funcionam e os problemas que você pode enfrentar ao implementá-los.
A Wikipedia ainda é a melhor: http://en.wikipedia.org/wiki/Mixin
fonte
Um mixin é uma forma limitada de herança múltipla. Em algumas linguagens, o mecanismo para adicionar um mixin a uma classe é um pouco diferente (em termos de sintaxe) do de herança.
Especialmente no contexto do Python, um mixin é uma classe pai que fornece funcionalidade às subclasses, mas não se destina a ser instanciado.
O que pode fazer você dizer: "isso é apenas herança múltipla, não realmente uma mixin" é se a classe que pode ser confundida para uma mixin pode realmente ser instanciada e usada - então, de fato, é uma diferença semântica e muito real.
Exemplo de herança múltipla
Este exemplo, da documentação , é um OrderedCounter:
Subclassifica o
Counter
e oOrderedDict
docollections
módulo.Ambos
Counter
eOrderedDict
devem ser instanciados e usados por conta própria. No entanto, ao subclassificar os dois, podemos ter um contador que é ordenado e reutiliza o código em cada objeto.Essa é uma maneira poderosa de reutilizar código, mas também pode ser problemática. Se ocorrer um erro em um dos objetos, corrigi-lo sem cuidado pode criar um erro na subclasse.
Exemplo de um Mixin
Os mixins geralmente são promovidos como a maneira de obter a reutilização de código sem possíveis problemas de acoplamento que a herança múltipla cooperativa, como o OrderedCounter, poderia ter. Ao usar mixins, você usa funcionalidades que não são tão fortemente acopladas aos dados.
Ao contrário do exemplo acima, um mixin não se destina a ser usado por si só. Ele fornece funcionalidade nova ou diferente.
Por exemplo, a biblioteca padrão possui algumas mixins na
socketserver
biblioteca .Nesse caso, os métodos mixin substituem os métodos na
UDPServer
definição de objeto para permitir a simultaneidade.O método substituído parece ser
process_request
e também fornece outro métodoprocess_request_thread
,. Aqui está do código fonte :Um exemplo inventado
Esta é uma combinação que é principalmente para fins de demonstração - a maioria dos objetos evolui além da utilidade desse repr:
e uso seria:
E uso:
fonte
Eu acho que houve algumas boas explicações aqui, mas eu queria fornecer outra perspectiva.
No Scala, você pode fazer mixins como foi descrito aqui, mas o que é muito interessante é que os mixins são realmente 'fundidos' para criar um novo tipo de classe da qual herdar. Em essência, você não herda de várias classes / mixins, mas gera um novo tipo de classe com todas as propriedades do mixin para herdar. Isso faz sentido, pois o Scala é baseado na JVM, na qual a herança múltipla não é atualmente suportada (a partir do Java 8). Esse tipo de classe mixin, a propósito, é um tipo especial chamado Trait in Scala.
É sugerido na maneira como uma classe é definida: a classe NewClass estende FirstMixin com SecondMixin com ThirdMixin ...
Não tenho certeza se o intérprete CPython faz o mesmo (mixin composição de classe), mas não ficaria surpreso. Além disso, vindo de um background em C ++, eu não chamaria um ABC ou 'interface' equivalente a um mixin - é um conceito semelhante, mas divergente em uso e implementação.
fonte
Eu não recomendaria mix-ins no novo código Python, se você puder encontrar outra maneira de contornar isso (como composição em vez de herança, ou apenas métodos de correção de macaco em suas próprias classes) que não são muito mais esforço.
Nas aulas de estilo antigo, você pode usar os mix-ins como uma maneira de pegar alguns métodos de outra classe. Mas, no mundo do novo estilo, tudo, até o mix, herda
object
. Isso significa que qualquer uso de herança múltipla naturalmente introduz problemas de MRO .Existem maneiras de fazer o MRO de herança múltipla funcionar em Python, principalmente a função super (), mas isso significa que você deve executar toda a hierarquia de classes usando super (), e é consideravelmente mais difícil entender o fluxo de controle.
fonte
Talvez alguns exemplos ajudem.
Se você está construindo uma classe e deseja que ela atue como um dicionário, você pode definir todos os vários
__ __
métodos necessários. Mas isso é um pouco de dor. Como alternativa, você pode apenas definir alguns e herdar (além de qualquer outra herança) deUserDict.DictMixin
(movido paracollections.DictMixin
em py3k). Isso terá o efeito de definir automaticamente todo o restante da API do dicionário.Um segundo exemplo: o kit de ferramentas da GUI wxPython permite que você faça controles de lista com várias colunas (como, por exemplo, a exibição do arquivo no Windows Explorer). Por padrão, essas listas são bastante básicas. Você pode adicionar funcionalidades adicionais, como a capacidade de classificar a lista por uma coluna específica, clicando no cabeçalho da coluna, herdando do ListCtrl e adicionando mixins apropriados.
fonte
Não é um exemplo de Python, mas na linguagem de programação D o termo
mixin
é usado para se referir a uma construção usada da mesma maneira; adicionando uma pilha de coisas a uma classe.Em D (que, aliás, não executa MI), isso é feito inserindo um modelo (pense em macros sintaticamente conscientes e seguras e você estará próximo) em um escopo. Isso permite que uma única linha de código em uma classe, estrutura, função, módulo ou qualquer outra seja expandida para qualquer número de declarações.
fonte
O OP mencionou que nunca ouviu falar de mixin em C ++, talvez seja porque eles são chamados CRTP (Curiously Recurring Template Pattern) em C ++. Além disso, @Ciro Santilli mencionou que o mixin é implementado via classe base abstrata em C ++. Embora a classe base abstrata possa ser usada para implementar mixin, é um exagero, pois a funcionalidade da função virtual em tempo de execução pode ser alcançada usando o modelo em tempo de compilação, sem a sobrecarga da pesquisa da tabela virtual em tempo de execução.
O padrão CRTP é descrito em detalhes aqui
Eu converti o exemplo python na resposta de @Ciro Santilli em C ++ usando a classe de modelo abaixo:
EDIT: Adicionado construtor protegido no ComparableMixin para que ele possa ser herdado e não instanciado. Atualizado o exemplo para mostrar como o construtor protegido causará erro de compilação quando um objeto do ComparableMixin é criado.
fonte
Talvez um exemplo do ruby possa ajudar:
Você pode incluir o mixin
Comparable
e definir uma função"<=>(other)"
, o mixin fornece todas essas funções:Faz isso invocando
<=>(other)
e devolvendo o resultado certo."instance <=> other"
retorna 0 se os dois objetos forem iguais, menor que 0 seinstance
for maior queother
e maior que 0 seother
for maior.fonte
__lt__
como base em vez de__cmp__
, a última delas é realmente obsoleta e desencorajada de usar. Para mim, parece mais simples de usar que mixin em vez de bastante complicado decoradores (parte de functools ) - embora este pode ser capaz de reagir de forma mais dinâmica em que as comparações são fornecidos ...O mixin fornece uma maneira de adicionar funcionalidade em uma classe, ou seja, você pode interagir com os métodos definidos em um módulo, incluindo o módulo na classe desejada. Embora o ruby não suporte herança múltipla, fornece mixin como uma alternativa para conseguir isso.
Aqui está um exemplo que explica como a herança múltipla é alcançada usando o mixin.
fonte
Eu apenas usei um python mixin para implementar testes de unidade para ordenadores python. Normalmente, um milter conversa com um MTA, dificultando o teste de unidade. O mix de teste substitui os métodos que conversam com o MTA e cria um ambiente simulado orientado por casos de teste.
Portanto, você adota um aplicativo milter não modificado, como spfmilter, e mixin TestBase, assim:
Em seguida, use TestMilter nos casos de teste para o aplicativo milter:
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
fonte
Acho que as respostas anteriores definiram muito bem o que são os MixIns . No entanto, para entendê-los melhor, pode ser útil comparar MixIns com Classes e Interfaces Abstratas da perspectiva do código / implementação:
1. Classe Abstrata
Classe que precisa conter um ou mais métodos abstratos
A classe Abstract pode conter métodos de estado (variáveis de instância) e não-abstratos
2. Interface
3. MixIns
No Python, por exemplo, essas são apenas convenções, porque todas as opções acima são definidas como
class
es. No entanto, o recurso comum das Classes Abstratas, Interfaces e MixIns é que elas não devem existir por si próprias, ou seja, não devem ser instanciadas.fonte
Eu li que você tem um histórico de ac #. Portanto, um bom ponto de partida pode ser uma implementação combinada para o .NET.
Você pode querer verificar o projeto codeplex em http://remix.codeplex.com/
Assista ao link do Simpósio lang.net para obter uma visão geral. Ainda há mais documentação disponível na página codeplex.
cumprimentos Stefan
fonte