¿Cuáles son las diferencias entre estos dos fragmentos de código?
Utilizando type()
:
import types
if type(a) is types.DictType:
do_something()
if type(b) in types.StringTypes:
do_something_else()
Utilizando isinstance()
:
if isinstance(a, dict):
do_something()
if isinstance(b, str) or isinstance(b, unicode):
do_something_else()
python
oop
inheritance
types
abad
fuente
fuente
str
yunicode
(donde solo puede verificarbasestring
), puede usar una tupla para verificar contra varios tipos. Para comprobar sisomething
esint
ostr
usarisinstance(something, (int, str))
.Respuestas:
Para resumir el contenido de otras respuestas (¡ya buenas!),
isinstance
Atiende la herencia (una instancia de una clase derivada también es una instancia de una clase base), mientras que verifica la igualdad detype
no (exige la identidad de los tipos y rechaza las instancias de subtipos, subclases de AKA).Normalmente, en Python, desea que su código admita la herencia, por supuesto (dado que la herencia es muy útil, sería malo evitar que el código que usa el suyo lo use), por lo que
isinstance
es menos malo que verificar la identidad detype
s porque admite perfectamente herencia.Eso no
isinstance
es bueno , eso sí, es menos malo que verificar la igualdad de tipos. La solución normal, Pythonic, preferida es casi invariablemente "escribir pato": intente usar el argumento como si fuera de un cierto tipo deseado, hágalo en una declaracióntry
/except
capturando todas las excepciones que podrían surgir si el argumento no fuera en realidad tipo (o cualquier otro tipo muy bien imitándolo ;-), y en laexcept
cláusula, intente otra cosa (usando el argumento "como si" fuera de otro tipo).basestring
es , sin embargo, un caso bastante especial: un tipo integrado que existe solo para permitirle usarisinstance
(ambosstr
y launicode
subclasebasestring
). Las cadenas son secuencias (puede recorrerlas, indexarlas, dividirlas, ...), pero generalmente desea tratarlas como tipos "escalares"; es algo incómodo (pero un caso de uso razonablemente frecuente) para tratar todo tipo de cadenas (y tal vez otros tipos escalares, es decir, aquellos en los que no puede hacer un bucle) de una manera, todos los contenedores (listas, conjuntos, dictos, ...) de otra manera, ybasestring
además loisinstance
ayuda a hacer eso: la estructura general de este el idioma es algo como:Se podría decir que
basestring
es una clase base abstracta ("ABC"): no ofrece una funcionalidad concreta para las subclases, sino que existe como un "marcador", principalmente para su usoisinstance
. El concepto obviamente está creciendo en Python, ya que PEP 3119 , que presenta una generalización del mismo, fue aceptado y se implementó a partir de Python 2.6 y 3.0.El PEP deja en claro que, si bien los ABC a menudo pueden sustituir la tipificación de patos, generalmente no existe una gran presión para hacerlo (ver aquí ). Sin embargo, el ABC implementado en versiones recientes de Python ofrece extras:
isinstance
(yissubclass
) ahora puede significar más que simplemente "[una instancia de] una clase derivada" (en particular, cualquier clase puede "registrarse" con un ABC para que sea mostrar como una subclase y sus instancias como instancias de ABC); y ABC también puede ofrecer una conveniencia adicional a las subclases reales de una manera muy natural a través de las aplicaciones de patrones de diseño de Método de plantilla (vea aquí y aquí [[parte II]] para obtener más información sobre TM DP, en general y específicamente en Python, independientemente de ABC) .Para conocer la mecánica subyacente del soporte ABC como se ofrece en Python 2.6, consulte aquí ; para su versión 3.1, muy similar, ver aquí . En ambas versiones, las colecciones de módulos de biblioteca estándar (esa es la versión 3.1; para la versión 2.6 muy similar, consulte aquí ) ofrece varios ABC útiles.
Para el propósito de esta respuesta, la clave para retener sobre ABC (más allá de una ubicación posiblemente más natural para la funcionalidad TM DP, en comparación con la alternativa clásica Python de clases mixin como UserDict.DictMixin ) es que hacen
isinstance
(yissubclass
) mucho más atractivo y generalizado (en Python 2.6 y en adelante) de lo que solían ser (en 2.5 y anteriores), y por lo tanto, por el contrario, hacer que la verificación de la igualdad de tipos sea una práctica aún peor en las versiones recientes de Python de lo que solía ser.fuente
Aquí hay un ejemplo donde
isinstance
logra algo quetype
no puede:en este caso, un objeto de camión es un Vehículo, pero obtendrá esto:
En otras palabras, también
isinstance
es cierto para las subclases.Ver también: ¿Cómo comparar el tipo de un objeto en Python?
fuente
type
está en desuso, useisinstance
en su lugar" a primera vista. por ejemplo, lo que quería eratype()
verificar exactamente , pero me engañaron por un corto tiempo (y tuve que depurar un poco) por esa razón.type()
y noisinstance()
. Uno no es mejor; Son para diferentes cosas.Verificación de tipo con
permite instancias de subclases y múltiples bases posibles:
mientras que la verificación de tipo con
solo admite el tipo al que se hace referencia.
Como nota al margen,
is
es probable que sea más apropiado queporque las clases son singletons.
Evite la verificación de tipos: utilice el polimorfismo (tipificación de pato)
En Python, por lo general, desea permitir cualquier tipo de argumentos, tratarlo como se espera y, si el objeto no se comporta como se espera, generará un error apropiado. Esto se conoce como polimorfismo, también conocido como tipeo de pato.
Si el código anterior funciona, podemos suponer que nuestro argumento es un pato. Así podemos pasar en otras cosas son subtipos reales de pato:
o que funcionan como un pato:
y nuestro código aún funciona.
Sin embargo, hay algunos casos en los que es conveniente hacer una verificación de tipo explícita. Quizás tenga cosas sensatas que hacer con diferentes tipos de objetos. Por ejemplo, el objeto Pandas Dataframe se puede construir a partir de dictados o registros. En tal caso, su código necesita saber qué tipo de argumento está obteniendo para poder manejarlo adecuadamente.
Entonces, para responder la pregunta:
¿Diferencias entre
isinstance()
ytype()
en Python?Permítame demostrar la diferencia:
type
Digamos que necesita garantizar un cierto comportamiento si su función obtiene un cierto tipo de argumento (un caso de uso común para los constructores). Si marca un tipo como este:
Si tratamos de pasar un dict que es una subclase de
dict
(como deberíamos poder, si esperamos que nuestro código siga el principio de la sustitución de Liskov , que los subtipos pueden ser sustituidos por tipos) nuestro código se rompe:plantea un error!
isinstance
¡Pero si usamos
isinstance
, podemos apoyar la sustitución de Liskov !:devoluciones
OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
Clases base abstractas
De hecho, podemos hacerlo aún mejor.
collections
proporciona clases base abstractas que aplican protocolos mínimos para varios tipos. En nuestro caso, si solo esperamos elMapping
protocolo, podemos hacer lo siguiente, y nuestro código se vuelve aún más flexible:Respuesta al comentario:
Sí, puede probar la igualdad de tipos, pero en lugar de lo anterior, use las bases múltiples para el flujo de control, a menos que solo permita específicamente esos tipos:
La diferencia, una vez más, es que
isinstance
admite subclases que pueden ser sustituidas por el padre sin interrumpir el programa, una propiedad conocida como sustitución de Liskov.Sin embargo, aún mejor, invierta sus dependencias y no compruebe ningún tipo específico.
Conclusión
Entonces, dado que queremos admitir la sustitución de subclases, en la mayoría de los casos, queremos evitar la verificación de tipo con
type
y preferimos la verificación de tipo conisinstance
, a menos que realmente necesite conocer la clase precisa de una instancia.fuente
isinstance(instance, y)
y usafrom v.w.x import y
, e importa esa verificación, pero cuando crea una instancia deinstance
uso enfrom x import y
lugar de cómo se importó y en your_module.py, la verificación de instancia fallará, aunque sea la misma clase.Se prefiere este último porque manejará las subclases correctamente. De hecho, su ejemplo se puede escribir aún más fácilmente porque
isinstance()
el segundo parámetro puede ser una tupla:o, usando la
basestring
clase abstracta:fuente
De acuerdo con la documentación de Python, aquí hay una declaración:
Por
isinstance()
lo tanto, debe preferirse sobretype()
.fuente
Una diferencia práctica de uso es cómo manejan
booleans
:True
yFalse
son solo palabras clave que significan1
y0
en python. Así,y
ambos regresan
True
. Ambos booleanos son una instancia de un entero.type()
, sin embargo, es más inteligente:vuelve
False
.fuente
Para las diferencias reales, podemos encontrarlo
code
, pero no puedo encontrar la implementación del comportamiento predeterminado deisinstance()
.Sin embargo, podemos obtener una similar abc .__ instancecheck__ de acuerdo con __instancecheck__ .
Desde arriba
abc.__instancecheck__
, después de usar la prueba a continuación:Llego a esta conclusión, para
type
:Para
isinstance
:Por cierto: mejor no mezclar el uso
relative and absolutely import
, useabsolutely import
from project_dir (agregado porsys.path
)fuente