Pregunta

¿Cuál es la mejor manera de verificar si un objeto dado es de un tipo dado? ¿Qué hay de verificar si el objeto se hereda de un tipo dado?

Digamos que tengo un objeto o . ¿Cómo puedo comprobar si es un str ?

¿Fue útil?

Solución

Para verificar si o es una instancia de str o cualquier subclase de str , use isinstance (esta sería la " canónica " manera):

if isinstance(o, str):

Para verificar si el tipo de o es exactamente str (excluye las subclases):

if type(o) is str:

Lo siguiente también funciona, y puede ser útil en algunos casos:

if issubclass(type(o), str):

Consulte Funciones integradas en la Referencia de la biblioteca de Python para obtener información relevante.

Una nota más: en este caso, si estás usando python 2, es posible que desees usar:

if isinstance(o, basestring):

porque esto también detectará cadenas Unicode ( unicode no es una subclase de str ; tanto str como unicode son subclases de basestring ). Tenga en cuenta que basestring ya no existe en python 3, donde hay una separación estricta de cadenas ( str ) y datos binarios ( bytes ).

Alternativamente, isinstance acepta una tupla de clases. Esto devolverá True si x es una instancia de cualquier subclase de cualquiera de (str, unicode):

if isinstance(o, (str, unicode)):

Otros consejos

La forma más de Pythonic de verificar el tipo de un objeto es ... no verificarlo.

Como Python recomienda Duck Typing , solo debes intentar ... excepto para usar los métodos del objeto de la manera que usted quiere usarlos. Entonces, si su función está buscando un objeto de archivo grabable, no verifique que sea una subclase de archivo , solo intente usar su .write () método!

Por supuesto, a veces estas bonitas abstracciones se descomponen y isinstance (obj, cls) es lo que necesita. Pero usar con moderación.

isinstance (o, str) devolverá True si o es un str o es de un tipo que hereda de str .

type (o) is str devolverá True si y solo si o es una str. Devolverá False si o es de un tipo que se hereda de str .

Luego de que se hizo y respondió la pregunta, se agregaron sugerencias de tipo a Python . Las sugerencias de tipo en Python permiten que los tipos se verifiquen, pero de una manera muy diferente a los idiomas tipificados estáticamente. Las sugerencias de tipo en Python asocian los tipos de argumentos esperados con funciones como datos accesibles en tiempo de ejecución asociados con funciones y esto permite verificar los tipos. Ejemplo de sintaxis de tipo de sugerencia:

def foo(i: int):
    return i

foo(5)
foo('oops')

En este caso, queremos que se genere un error para foo ('oops') ya que el tipo anotado del argumento es int . La sugerencia de tipo agregada no causa que se produzca un error cuando el script se ejecuta normalmente. Sin embargo, agrega atributos a la función que describe los tipos esperados que otros programas pueden consultar y usar para verificar errores de tipo.

Uno de estos otros programas que se pueden usar para encontrar el error de tipo es mypy :

mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"

(Es posible que debas instalar mypy desde tu administrador de paquetes. No creo que venga con CPython, pero parece tener cierto nivel de "oficialidad").

La comprobación de tipos de esta manera es diferente de la comprobación de tipos en lenguajes compilados tipificados estáticamente. Debido a que los tipos son dinámicos en Python, la verificación de tipos debe realizarse en tiempo de ejecución, lo que impone un costo, incluso en los programas correctos, si insistimos en que ocurra en cada oportunidad. Las comprobaciones explícitas de tipo también pueden ser más restrictivas de lo necesario y causar errores innecesarios (por ejemplo, ¿el argumento realmente debe ser exactamente del tipo list o es algo lo suficientemente iterable?).

La ventaja de la comprobación explícita de tipos es que puede detectar errores antes y dar mensajes de error más claros que la tipificación de pato. Los requisitos exactos de un tipo de pato solo pueden expresarse con documentación externa (con suerte es exhaustiva y precisa) y los errores de tipos incompatibles pueden ocurrir lejos de donde se originan.

Las sugerencias de tipo de Python están destinadas a ofrecer un compromiso donde los tipos se pueden especificar y verificar, pero no hay costo adicional durante la ejecución del código habitual.

El paquete typing ofrece variables de tipo que se pueden usar en sugerencias de tipo para expresar los comportamientos necesarios sin necesidad de tipos particulares. Por ejemplo, incluye variables como Iterable y Callable para que las sugerencias especifiquen la necesidad de cualquier tipo con esos comportamientos.

Si bien las sugerencias de tipo son la forma más Pythonic de verificar tipos, a menudo es incluso más Pythonic para no verificar tipos y confiar en la tipificación de pato. Las sugerencias de tipo son relativamente nuevas y el jurado aún está deliberando sobre cuándo son la solución más Pythonic. Una comparación relativamente incontrovertida pero muy general: las sugerencias de tipo proporcionan una forma de documentación que se puede aplicar, permiten que el código se genere antes y es más fácil de entender los errores, puede detectar errores que la tipificación no puede y se puede verificar de forma estática (de forma inusual). sentido pero todavía está fuera del tiempo de ejecución). Por otro lado, la tipificación de pato ha sido la forma de Pythonic durante mucho tiempo, no impone la sobrecarga cognitiva de tipificación estática, es menos detallada y aceptará todos los tipos viables y algunos.

Aquí hay un ejemplo de por qué la escritura de pato es mala sin saber cuándo es peligroso. Por ejemplo: Aquí está el código de Python (posiblemente omitiendo la sangría adecuada), tenga en cuenta que esto La situación se puede evitar cuidando las funciones de instancia y de clase para asegurarse de que cuando realmente necesita un pato, no reciba una bomba.

class Bomb:
    def __init__(self):
        ""

    def talk(self):
        self.explode()

    def explode(self):
        print "BOOM!, The bomb explodes."

class Duck:
    def __init__(self):
        ""
    def talk(self):
        print "I am a duck, I will not blow up if you ask me to talk."    

class Kid:
    kids_duck = None

    def __init__(self):
        print "Kid comes around a corner and asks you for money so he could buy a duck."

    def takeDuck(self, duck):
        self.kids_duck = duck
        print "The kid accepts the duck, and happily skips along"

    def doYourThing(self):
        print "The kid tries to get the duck to talk"
        self.kids_duck.talk()

myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()
isinstance(o, str)

Enlace a documentos

Creo que lo mejor de usar un lenguaje dinámico como Python es que realmente no deberías tener que revisar algo así.

Simplemente llamaría a los métodos requeridos en su objeto y detectaría un AttributeError . Más adelante, esto le permitirá llamar a sus métodos con otros objetos (aparentemente no relacionados) para realizar diferentes tareas, como burlarse de un objeto para probar.

Lo he usado mucho cuando obtengo datos de la web con urllib2.urlopen () , que devuelve un objeto file like . A su vez, esto se puede pasar a casi cualquier método que se lea desde un archivo, porque implementa el mismo método read () como un archivo real.

Pero estoy seguro de que hay un momento y un lugar para usar isinstance () , de lo contrario probablemente no estaría allí :)

A Hugo:

Probablemente te refieres a list en lugar de array , pero eso apunta a todo el problema de la verificación de tipos: no quieres saber si el objeto en cuestión es un En la lista, desea saber si es algún tipo de secuencia o si es un solo objeto. Así que intenta usarlo como una secuencia.

Diga que desea agregar el objeto a una secuencia existente, o si es una secuencia de objetos, agréguelos todos

try:
   my_sequence.extend(o)
except TypeError:
  my_sequence.append(o)

Un truco con esto es si está trabajando con cadenas y / o secuencias de cadenas; eso es complicado, ya que una cadena a menudo se considera como un solo objeto, pero también es una secuencia de caracteres. Peor que eso, ya que es realmente una secuencia de cadenas de una sola longitud.

Por lo general, elijo diseñar mi API para que solo acepte un solo valor o una secuencia, lo que facilita las cosas. No es difícil colocar un [] alrededor de su valor único cuando lo pasa, si es necesario.

(Aunque esto puede causar errores con las cadenas, ya que se ven como (son) secuencias).

Para validaciones de tipo más complejas, me gusta el enfoque de typeguard de la validación basada en anotaciones de pistas de tipo python :

from typeguard import check_type
from typing import List

try:
    check_type('mylist', [1, 2], List[int])
except TypeError as e:
    print(e)

Puede realizar validaciones muy complejas de manera muy limpia y legible.

check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo) 

Puede verificar con la línea de abajo para ver qué tipo de carácter es el valor dado:

def chr_type(chrx):
    if chrx.isalpha()==True:
        return 'alpha'
    elif chrx.isdigit()==True:
        return 'numeric'
    else:
        return 'nothing'

chr_type("12)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top