¿Cuáles son las diferencias entre type () e isinstance ()?

¿Cuáles son las diferencias entre estos dos fragmentos de código?

Usar type():

import types

if type(a) is types.DictType:
    do_something()
if type(b) in types.StringTypes:
    do_something_else()

Usar isinstance():

if isinstance(a, dict):
    do_something()
if isinstance(b, str) or isinstance(b, unicode):
    do_something_else()

preguntado Oct 11 '09, 00:10

Nota: si no es str y unicode (donde puedes comprobar basestring), puede utilizar una tupla para comparar varios tipos. Para comprobar si something is int or str utilizan el isinstance(something, (int, str)). -

type() devuelve el tipo de objeto que introdujiste como argumento y, por lo general, no es útil a menos que se compare con un tipo real (como type(9) == int). isinstance() devuelve un valor booleano (verdadero o falso) en función de si el objeto es de un tipo determinado. isinstance suele ser más elegante de usar en lugar de escribir una verificación de igualdad desordenada, en la mayoría de los casos. -

7 Respuestas

Para resumir el contenido de otras respuestas (¡ya buenas!), isinstance atiende la herencia (una instancia de una clase derivada es un instancia de una clase base, también), mientras se comprueba la igualdad de type no lo hace (exige identidad de tipos y rechaza instancias de subtipos, también conocidas como subclases).

Normalmente, en Python, desea que su código admita la herencia, por supuesto (dado que la herencia es tan útil, ¡sería malo evitar que el código que usa el suyo lo use!), Así que isinstance es menos malo que comprobar la identidad de types porque admite la herencia sin problemas.

No es eso isinstance is bueno, fíjate, es solo menos mal que comprobar la igualdad de tipos. La solución normal, Pythonic, preferida es casi invariablemente "escribir pato": intente usar el argumento como si era de un cierto tipo deseado, hágalo en un try/except declaración que captura todas las excepciones que podrían surgir si el argumento no fuera de ese tipo (o cualquier otro tipo imitándolo bien ;-), y en el except cláusula, pruebe con otra cosa (utilizando el argumento "como si" fuera de otro tipo).

basestring is, sin embargo, es un caso bastante especial: un tipo incorporado que existe , solamente para dejarte usar isinstance (Tanto str y unicode Subclase basestring). Las cadenas son secuencias (puede recorrerlas, indexarlas, cortarlas, ...), pero generalmente desea tratarlas como tipos "escalares"; es algo incómodo (pero un caso de uso razonablemente frecuente) tratar todo tipo de cadenas (y tal vez otros tipos escalares, es decir, aquellos en los que no puede realizar un bucle) de una manera, todos los contenedores (listas, conjuntos, dictados, ...) de otra manera basestring y también isinstance te ayuda a hacer eso; la estructura general de este idioma es algo como:

if isinstance(x, basestring)
  return treatasscalar(x)
try:
  return treatasiter(iter(x))
except TypeError:
  return treatasscalar(x)

Podrías decirlo basestring es un Clase base abstracta ("ABC"): no ofrece ninguna funcionalidad concreta a las subclases, sino que existe como un "marcador", principalmente para su uso con isinstance. El concepto es obviamente creciente en Python, ya que PEP 3119, que introduce una generalización del mismo, fue aceptado y se ha implementado a partir de Python 2.6 y 3.0.

El PEP deja en claro que, si bien el ABC a menudo puede sustituir a la tipificación de pato, generalmente no hay una gran presión para hacerlo (ver aquí). Sin embargo, los ABC implementados en las versiones recientes de Python ofrecen ventajas adicionales: isinstance (y issubclass) ahora puede significar más que simplemente "[una instancia de] una clase derivada" (en particular, cualquier clase puede "registrarse" con un ABC para que se muestre como una subclase, y sus instancias como instancias del ABC); y ABC también pueden ofrecer una conveniencia adicional a las subclases reales de una manera muy natural a través de las aplicaciones de patrones de diseño del método de plantilla (ver aquí y aquí [[parte II]] para 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 que se ofrece en Python 2.6, consulte aquí; para su versión 3.1, muy similar, vea aquí. En ambas versiones, módulo de biblioteca estándar colecciones (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, lo clave para retener sobre ABC (más allá de una ubicación posiblemente más natural para la funcionalidad de TM DP, en comparación con la alternativa clásica de Python de clases mixtas como UserDict.DictMixin) es que hacen isinstance (y issubclass) mucho más atractivo y omnipresente (en Python 2.6 y en el futuro) de lo que solían ser (en 2.5 y antes), y por lo tanto, por el contrario, hacen 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 .

Respondido el 18 de diciembre de 17 a las 20:12

No es que un ejemplo sea bueno, fíjate, es menos malo que comprobar la igualdad de tipos. La solución normal, Pythonic, preferida es casi invariablemente "tipificación de pato". Esta es una vista bastante limitada: hay buenos casos para usar isinstance () en, digamos, un intérprete donde los tipos reflejan la gramática. ¡Ser "Pythonic" no lo es todo! - Gene Callahan

cadena base no está disponible en Python 3. - erobertc

@GeneCallahan, porque hay muy buenos casos, no significa que lo que se dijo no sea una buena regla general. Estoy de acuerdo en que verificar el tipo con anticipación definitivamente tiene su lugar, pero dejar que los patos graznen debería cubrir la mayor casos de manera más flexible y eficiente. - Eric Ed Lohmar

@erobertc, según Novedades de Python 3.0, "Se eliminó el tipo abstracto de cadena base incorporada. Use str en su lugar." - neurita

Lo mismo ocurre con el tipo Unicode. "Python 3.0 utiliza los conceptos de texto y datos (binarios) en lugar de cadenas Unicode y cadenas de 8 bits. Todo el texto es Unicode; sin embargo, Unicode codificado se representa como datos binarios". - Robar

Aquí hay un ejemplo donde isinstance logra algo que type no puedo:

class Vehicle:
    pass

class Truck(Vehicle):
    pass

en este caso, un objeto de camión es un vehículo, pero obtendrá esto:

isinstance(Vehicle(), Vehicle)  # returns True
type(Vehicle()) == Vehicle      # returns True
isinstance(Truck(), Vehicle)    # returns True
type(Truck()) == Vehicle        # returns False, and this probably won't be what you want.

En otras palabras, isinstance también es cierto para las subclases.

Ver también: ¿Cómo comparar el tipo de un objeto en Python?

Respondido 02 Abr '19, 00:04

debido a que hay un caso en el que no desea el comportamiento de isInstance, yo diría que no hay "mejor". Simplemente hacen algo diferente. - philgo20

-1, porque "isinstance es mejor que type" es un comentario engañoso. se entiende como "type está en desuso, use isinstance en lugar "a primera vista. Por ejemplo, lo que quería era exactamente type() comprobando, pero fui engañado por un corto tiempo (y tuve que depurar un poco) por esa razón. - ceremonia

Es un buen ejemplo de cómo funcionan de manera diferente, pero me encontré con un caso en el que necesitaba específicamente type() y no isinstance(). Uno no es mejor; son para cosas diferentes. - EL_DON

Por favor, ¿puede decirme por qué ha utilizado == en lugar de "es"? - variable

@variable "devolverá True si dos variables apuntan al mismo objeto, == si los objetos a los que hacen referencia las variables son iguales". Ver esta SO publicación. No estoy seguro de si importa en el contexto de esta respuesta. - Luke Smith

Diferencias entre isinstance() y type() en Python?

Verificación de tipo con

isinstance(obj, Base)

permite instancias de subclases y múltiples bases posibles:

isinstance(obj, (Base1, Base2))

mientras que la verificación de tipos con

type(obj) is Base

solo admite el tipo al que se hace referencia.


Como nota al margen, is es probablemente más apropiado que

type(obj) == Base

porque las clases son singletons.

Evite la verificación de tipos: use polimorfismo (tipificación de pato)

En Python, por lo general, desea permitir cualquier tipo para sus argumentos, trátelo como se espera y, si el objeto no se comporta como se esperaba, generará un error apropiado. Esto se conoce como polimorfismo, también conocido como tipificación de pato.

def function_of_duck(duck):
    duck.quack()
    duck.swim()

Si el código anterior funciona, podemos suponer que nuestro argumento es un pato. Por lo tanto, podemos pasar otras cosas que son subtipos reales de pato:

function_of_duck(mallard)

o que funcionan como un pato:

function_of_duck(object_that_quacks_and_swims_like_a_duck)

y nuestro código todavía funciona.

Sin embargo, hay algunos casos en los que es conveniente realizar una verificación de tipo explícitamente. 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 or registros. En tal caso, su código necesita saber qué tipo de argumento está recibiendo para poder manejarlo adecuadamente.

Entonces, para responder a la pregunta:

Diferencias entre isinstance() y type() en Python?

Permítame demostrar la diferencia:

type

Supongamos 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 busca un tipo como este:

def foo(data):
    '''accepts a dict to construct something, string support in future'''
    if type(data) is not dict:
        # we're only going to test for dicts for now
        raise ValueError('only dicts are supported for now')

Si intentamos pasar un dict que es una subclase de dict (como deberíamos poder hacerlo, si esperamos que nuestro código siga el principio de Sustitución de Liskov, que los subtipos pueden ser sustituidos por tipos) ¡nuestro código se rompe !:

from collections import OrderedDict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

genera un error!

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in foo
ValueError: argument must be a dict

isinstance

Pero si usamos isinstance, podemos apoyar la sustitución de Liskov !:

def foo(a_dict):
    if not isinstance(a_dict, dict):
        raise ValueError('argument must be a dict')
    return a_dict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

devoluciones OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])

Clases base abstractas

De hecho, podemos hacerlo aún mejor. collections proporciona clases base abstractas que imponen protocolos mínimos para varios tipos. En nuestro caso, si solo esperamos Mapping protocolo, podemos hacer lo siguiente, y nuestro código se vuelve aún más flexible:

from collections import Mapping

def foo(a_dict):
    if not isinstance(a_dict, Mapping):
        raise ValueError('argument must be a dict')
    return a_dict

Respuesta al comentario:

Cabe señalar que el tipo se puede utilizar para comprobar contra varias clases utilizando type(obj) in (A, B, C)

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 específicamente solo permita esos tipos:

isinstance(obj, (A, B, C))

La diferencia, de nuevo, es que isinstance admite subclases que pueden sustituir al padre sin romper el programa, una propiedad conocida como sustitución de Liskov.

Aún mejor, sin embargo, invierta sus dependencias y no busque tipos específicos en absoluto.

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 tipos con type y prefiero la verificación de tipos con isinstance - a menos que realmente necesite saber la clase precisa de una instancia.

Respondido 26 ago 18, 13:08

Si tiene your_module.py donde busca isinstance(instance, y) y use from v.w.x import y, e importa ese cheque, pero cuando crea una instancia instance tu usas from x import y en lugar de cómo se importó y en your_module.py, la comprobación de isinstance fallará, aunque sea de la misma clase. - capitán del ejército

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:

if isinstance(b, (str, unicode)):
    do_something_else()

o, usando el basestring clase abstracta:

if isinstance(b, basestring):
    do_something_else()

Respondido 28 Oct 13, 15:10

Una diferencia de uso práctica es cómo se manejan booleans:

True y False son solo palabras clave que significan 1 y 0 en python. Por lo tanto,

isinstance(True, int)

y

isinstance(False, int)

ambos regresan True. Ambos valores booleanos son una instancia de un número entero. type(), sin embargo, es más inteligente:

type(True) == int

devoluciones False.

contestado el 25 de mayo de 19 a las 05:05

De acuerdo con la documentación de Python, aquí hay una declaración:

8.15. tipos: nombres para tipos integrados

A partir de Python 2.2, funciones integradas de fábrica como int() y str() también son nombres para los tipos correspondientes.

So isinstance() debería ser preferido sobre type().

Respondido el 24 de Septiembre de 13 a las 18:09

Para conocer las diferencias reales, podemos encontrarlo en code, pero no puedo encontrar la implementación del comportamiento predeterminado del isinstance().

Sin embargo, podemos obtener uno similar. abc .__ instancecheck__ según __control de instancia__.

Desde arriba abc.__instancecheck__, después de usar la prueba a continuación:

# file tree
# /test/__init__.py
# /test/aaa/__init__.py
# /test/aaa/aa.py
class b():
pass

# /test/aaa/a.py
import sys
sys.path.append('/test')

from aaa.aa import b
from aa import b as c

d = b()

print(b, c, d.__class__)
for i in [b, c, object]:
    print(i, '__subclasses__',  i.__subclasses__())
    print(i, '__mro__', i.__mro__)
    print(i, '__subclasshook__', i.__subclasshook__(d.__class__))
    print(i, '__subclasshook__', i.__subclasshook__(type(d)))
print(isinstance(d, b))
print(isinstance(d, c))

<class 'aaa.aa.b'> <class 'aa.b'> <class 'aaa.aa.b'>
<class 'aaa.aa.b'> __subclasses__ []
<class 'aaa.aa.b'> __mro__ (<class 'aaa.aa.b'>, <class 'object'>)
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasses__ []
<class 'aa.b'> __mro__ (<class 'aa.b'>, <class 'object'>)
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'object'> __subclasses__ [..., <class 'aaa.aa.b'>, <class 'aa.b'>]
<class 'object'> __mro__ (<class 'object'>,)
<class 'object'> __subclasshook__ NotImplemented
<class 'object'> __subclasshook__ NotImplemented
True
False

Llego a esta conclusión, porque type:

# according to `abc.__instancecheck__`, they are maybe different! I have not found negative one 
type(INSTANCE) ~= INSTANCE.__class__
type(CLASS) ~= CLASS.__class__

Para isinstance:

# guess from `abc.__instancecheck__`
return any(c in cls.__mro__ or c in cls.__subclasses__ or cls.__subclasshook__(c) for c in {INSTANCE.__class__, type(INSTANCE)})

Por cierto: mejor no mezclar el uso relative and absolutely import, Utilizar absolutely import from project_dir (agregado por sys.path)

contestado el 10 de mayo de 18 a las 09:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.