Quais são as diferenças entre esses dois fragmentos de código?
Usando type()
:
import types
if type(a) is types.DictType:
do_something()
if type(b) in types.StringTypes:
do_something_else()
Usando isinstance()
:
if isinstance(a, dict):
do_something()
if isinstance(b, str) or isinstance(b, unicode):
do_something_else()
python
oop
inheritance
types
abade
fonte
fonte
str
eunicode
(onde você pode apenas verificarbasestring
), você pode usar uma tupla para verificar vários tipos. Para verificar sesomething
éint
oustr
usarisinstance(something, (int, str))
.Respostas:
Para resumir o conteúdo de outras respostas (já boas!),
isinstance
Atende a herança (uma instância de uma classe derivada também é uma instância de uma classe base), enquanto a verificação da igualdade detype
não (exige identidade de tipos e rejeita instâncias) subtipos, subclasses AKA).Normalmente, em Python, você deseja que seu código ofereça suporte a herança, é claro (uma vez que a herança é muito útil, seria ruim interromper o código usando o seu!), Portanto,
isinstance
é menos ruim do que verificar a identidade detype
s, porque suporta perfeitamente herança.Não
isinstance
é bom , lembre-se - é menos ruim do que verificar a igualdade de tipos. A solução preferida normal, pitonica, é quase sempre "digitar pato": tente usar o argumento como se fosse de um determinado tipo desejado, faça-o em uma instruçãotry
/except
capturando todas as exceções que possam surgir se o argumento não for de fato aquele type (ou qualquer outro tipo que imite o pato ;-) e, naexcept
cláusula, tente outra coisa (usando o argumento "como se" fosse de outro tipo).basestring
é , no entanto, um caso bastante especial - um tipo interno que existe apenas para permitir o usoisinstance
(ambosstr
eunicode
subclassebasestring
). Strings são sequências (você pode fazer um loop sobre elas, indexá-las, cortá-las, ...), mas geralmente você deseja tratá-las como tipos "escalares" - é um pouco incoveniente (mas um caso de uso razoavelmente frequente) tratar todos os tipos de strings (e talvez outros tipos escalares, ou seja, aqueles em que você não pode executar um loop) de uma maneira, todos os contêineres (listas, conjuntos, dictos, ...) de outra maneira, ebasestring
mais oisinstance
ajudam a fazer isso - a estrutura geral deste idioma é algo como:Você poderia dizer que
basestring
é uma Classe Base Abstrata ("ABC") - ela não oferece funcionalidade concreta para subclasses, mas existe como um "marcador", principalmente para uso comisinstance
. O conceito é obviamente crescente no Python, desde que o PEP 3119 , que introduz uma generalização, foi aceito e foi implementado a partir do Python 2.6 e 3.0.O PEP deixa claro que, embora os ABCs possam substituir a digitação de patos, geralmente não há grande pressão para fazer isso (veja aqui ). Os ABCs implementados nas versões recentes do Python, no entanto, oferecem vantagens extras:
isinstance
(eissubclass
) agora podem significar mais do que apenas "[uma instância de] uma classe derivada" (em particular, qualquer classe pode ser "registrada" com um ABC para que mostrar como uma subclasse e suas instâncias como instâncias do ABC); e os ABCs também podem oferecer comodidade extra às subclasses reais de maneira muito natural, por meio de aplicativos de padrão de design do Método de Modelo (veja aqui e aqui [[parte II]] para obter mais informações sobre o TM DP, em geral e especificamente em Python, independente dos ABCs). .Para a mecânica subjacente do suporte ABC, conforme oferecido no Python 2.6, veja aqui ; para a versão 3.1, muito parecida, veja aqui . Nas duas versões, as coleções de módulos de biblioteca padrão (que é a versão 3.1 - para a versão 2.6 muito semelhante, veja aqui ) oferecem vários ABCs úteis.
Para os fins desta resposta, o principal a ser retido sobre os ABCs (além de um posicionamento mais natural para a funcionalidade TM DP, em comparação com a alternativa clássica do Python de classes mixin , como UserDict.DictMixin ), é que elas produzem
isinstance
(eissubclass
) muito mais atraente e difundido (no Python 2.6 e em diante) do que costumava ser (no 2.5 e antes) e, portanto, por outro lado, torna a verificação da igualdade de tipos uma prática ainda pior nas versões recentes do Python do que já era.fonte
Aqui está um exemplo em que
isinstance
obtém algo quetype
não pode:Nesse caso, um objeto de caminhão é um veículo, mas você verá o seguinte:
Em outras palavras, também
isinstance
é válido para subclasses.Veja também: Como comparar o tipo de um objeto no Python?
fonte
type
está obsoleto, use emisinstance
vez disso" à primeira vista. por exemplo, o que eu queria era exatamentetype()
verificar, mas fui enganado por um curto período de tempo (e tive que depurar um pouco) por esse motivo.type()
e nãoisinstance()
. Um não é melhor; eles são para coisas diferentes.Verificação de tipo com
permite instâncias de subclasses e várias bases possíveis:
Considerando que a verificação de tipo com
suporta apenas o tipo referenciado.
Como nota de rodapé,
is
é provavelmente mais apropriado do queporque as aulas são singletons.
Evite a verificação de tipo - use Polimorfismo (digitação de pato)
Em Python, geralmente você deseja permitir qualquer tipo para seus argumentos, tratá-lo como esperado e, se o objeto não se comportar conforme o esperado, isso gerará um erro apropriado. Isso é conhecido como polimorfismo, também conhecido como digitação de pato.
Se o código acima funcionar, podemos presumir que nosso argumento é um pato. Assim, podemos passar em outras coisas são sub-tipos reais de pato:
ou que funcionam como um pato:
e nosso código ainda funciona.
No entanto, há alguns casos em que é desejável verificar explicitamente o tipo. Talvez você tenha coisas sensatas a fazer com diferentes tipos de objetos. Por exemplo, o objeto Pandas Dataframe pode ser construído a partir de dictos ou registros. Nesse caso, seu código precisa saber que tipo de argumento está sendo recebido, para que ele possa manipulá-lo adequadamente.
Então, para responder à pergunta:
Diferenças entre
isinstance()
etype()
em Python?Permita-me demonstrar a diferença:
type
Digamos que você precise garantir um certo comportamento se sua função receber um certo tipo de argumento (um caso de uso comum para construtores). Se você verificar um tipo como este:
Se tentarmos passar um ditado que é uma subclasse de
dict
(como deveríamos ser, se esperamos que nosso código siga o princípio da substituição de Liskov , que subtipos podem ser substituídos por tipos), nosso código quebra !:gera um erro!
isinstance
Mas se usarmos
isinstance
, podemos apoiar a Substituição Liskov !:retorna
OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
Classes base abstratas
De fato, podemos fazer ainda melhor.
collections
fornece classes básicas abstratas que impõem protocolos mínimos para vários tipos. No nosso caso, se esperamos apenas oMapping
protocolo, podemos fazer o seguinte e nosso código se torna ainda mais flexível:Resposta ao comentário:
Sim, você pode testar a igualdade de tipos, mas, em vez do acima, use as várias bases para o fluxo de controle, a menos que você esteja especificamente permitindo apenas esses tipos:
A diferença, novamente, é que
isinstance
suporta subclasses que podem ser substituídas pelo pai sem interromper o programa, uma propriedade conhecida como substituição de Liskov.Melhor ainda, inverta suas dependências e não verifique tipos específicos.
Conclusão
Portanto, como queremos oferecer suporte à substituição de subclasses, na maioria dos casos, queremos evitar a verificação de
type
tipo e preferir a verificação de tipoisinstance
- a menos que você realmente precise conhecer a classe precisa de uma instância.fonte
isinstance(instance, y)
e usafrom v.w.x import y
, e importa essa verificação, mas quando instanciainstance
o uso, emfrom x import y
vez de como foi importado no seu_module.py, a verificação isinstance falhará, mesmo que seja da mesma classe.O último é preferido, porque ele manipulará subclasses corretamente. De fato, seu exemplo pode ser escrito ainda mais facilmente, porque
isinstance()
o segundo parâmetro pode ser uma tupla:ou, usando a
basestring
classe abstract:fonte
De acordo com a documentação do python, aqui está uma declaração:
Então,
isinstance()
deve ser preferíveltype()
.fonte
Uma diferença prática de uso é como eles lidam com
booleans
:True
eFalse
são apenas palavras-chave que significam1
e0
em python. Portanto,e
ambos retornam
True
. Ambos os booleanos são uma instância de um número inteiro.type()
, no entanto, é mais inteligente:retorna
False
.fonte
Para as diferenças reais, podemos encontrá-lo
code
, mas não consigo encontrar o implemento do comportamento padrão do arquivoisinstance()
.No entanto, podemos obter o semelhante abc .__ instancecheck__ de acordo com __instancecheck__ .
De cima
abc.__instancecheck__
, depois de usar o teste abaixo:Eu chego a esta conclusão, para
type
:Para
isinstance
:BTW: melhor não misturar uso
relative and absolutely import
, useabsolutely import
de project_dir (adicionado porsys.path
)fonte