Bueno, el enfoque canónico en Python es no verificar el tipo en absoluto (a menos que esté depurando). Por lo general, solo intenta usarlo como una cadena (por ejemplo, concatenar con otras cadenas, imprimir en la consola, etc.); Si cree que puede fallar, use try / except o hasattr. Dicho esto, la respuesta aceptada es la forma canónica de hacer lo que generalmente "no debería hacer" en el mundo de Python. Para obtener más información, busque en Google "Python duck typing" o lea estos: voidspace.org.uk/python/articles/duck_typing.shtml stackoverflow.com/questions/610883/…
Jon Coombs
99
Creo que el Sr. Coombs está pasando por alto ejemplos como clases serializables que no son JSON. Si coloca una gran cantidad de datos a través de una función (cuyo código no se puede influir), es posible que desee convertir ciertas partes de esos datos en, por ejemplo, un <str> antes de pasarlo. Al menos esa es la forma en que terminó en esta página ...
John Carrell
2
Parece que la razón más común para pedir esto es que uno quiere distinguir entre cadenas e iterables de cadenas. Esta es una pregunta difícil porque las cadenas son iterables de cadenas: una cadena de un solo carácter es incluso una secuencia de sí misma (la última vez que lo verifiqué, probablemente no debería confiar en ella). ¿Pero alguien alguna vez lo usaría para algo parecido a una cuerda? Sí . Entonces, la respuesta a "¿Qué debo hacer para distinguir entre cadenas y otros iterables de cadenas?" es correctamente: "Depende de lo que intentes hacer". :-D
clacke
2
Las anotaciones de tipo Python ahora son una cosa. Echa un vistazo a mypy
Sheena
Respuestas:
1522
Para verificar si oes una instancia stro alguna subclase de str, use isinstance (esta sería la forma "canónica"):
if isinstance(o, str):
Para verificar si el tipo de oes exactamente str(excluir 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 incorporadas en la Referencia de la biblioteca de Python para obtener información relevante.
Una nota más: en este caso, si está usando Python 2, es posible que desee usar:
if isinstance(o, basestring):
porque esto también capturará cadenas Unicode ( unicodeno es una subclase de str; ambas stry unicodeson subclases de basestring). Tenga en cuenta que basestringya no existe en Python 3, donde hay una separación estricta de cadenas ( str) y datos binarios ( bytes).
Alternativamente, isinstanceacepta una tupla de clases. Esto devolverá Truesi oes una instancia de cualquier subclase de cualquiera de (str, unicode):
str .__ subclasses __ () solo devuelve las subclases directas de str, y no hace lo mismo que issubclass () o isinstance (). (Para hacer eso, tendrías que llamar recursivamente .__ subclases __ ().
Thomas Wouters
15
Esta es una buena respuesta, pero creo que realmente debería comenzar con una advertencia de que generalmente no debería estar haciendo esto en Python. Tal como está, parece validar la suposición de que esto es "algo canónico que hacer en Python", lo cual no es así.
Jon Coombs
44
Estas son respuestas de python2. Por ejemplo, no hay una cadena base en python3.
dfrankow
44
¿Cuál es la diferencia entre instancia y "exactamente"? Si type(a) is Objectentonces no es cierto también eso isinstance(a, Object). Sin embargo, si type(a) is SubClassOfObject, entonces type(a) is Object == False, pero isinstance(a, Object) == True. ¿Derecha?
mavavilj
1
@mavavilj: a is bsignifica que ayb son exactamente lo mismo, es decir, referencias a la misma entidad en la memoria. Entonces, ay btendría que ser exactamente la misma clase, no subclases, como con isinstance(). Ver por ejemplo stackoverflow.com/a/133024/1072212
Terry Brown
196
La forma más pitónica de verificar el tipo de un objeto es ... no verificarlo.
Dado que Python alienta a Duck Typing , solo debe try...exceptusar los métodos del objeto de la forma en que desea usarlos. Entonces, si su función está buscando un objeto de archivo grabable, no verifique que sea una subclase de file, ¡solo intente usar su .write()método!
Por supuesto, a veces estas agradables abstracciones se descomponen y isinstance(obj, cls)es lo que necesitas. Pero use con moderación.
En mi humilde opinión, la forma más pitónica es hacer frente a cualquier argumento que se da. En mi código, a menudo no puedo saber si recibo un objeto o una matriz de objetos, y uso la verificación de tipos internamente para convertir un solo objeto en una lista de un elemento.
sastanin
14
En lugar de tratar de usar su método de escritura, hay momentos en que desea hacer esto sin causar una excepción. En este caso, podría hacer ... if hasattr(ob, "write") and callable(ob.write): O guardar algún acceso dict ...func = getattr(ob, "write", None)if callable(func): ...
ideasman42
142
La escritura de pato se trata de usar una biblioteca. La verificación de tipos se trata de escribir una biblioteca. No es el mismo problema de dominio.
RickyA
16
@RickyA, no estoy de acuerdo. La escritura de pato se trata de interactuar con objetos utilizando interfaces con semánticas bien conocidas. Esto puede aplicarse al código de la biblioteca o al código que usa dicha biblioteca.
Por supuesto, esto fallará si el objeto no es una instancia de 'str', sino de algo parecido a una cadena. Como unicode, mmap, UserString o cualquier otro tipo definido por el usuario. El enfoque habitual en Python es no hacer verificaciones de tipo.
Thomas Wouters
66
No tiene que disculparse, está bien responder su propia pregunta. SO es para las respuestas, no para el karma.
Eli Bendersky
2
Esto es muy útil. Porque la diferencia entre isinstancey type(var) == type('')no está clara.
sastanin
30
Después de hacer y responder la pregunta, se agregaron sugerencias de tipo a Python . Las sugerencias de tipo en Python permiten que se verifiquen los tipos, pero de una manera muy diferente a los lenguajes estáticos. 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 que se verifiquen los tipos. Ejemplo de sintaxis de sugerencia de tipo:
def foo(i: int):return i
foo(5)
foo('oops')
En este caso, queremos que se active un error foo('oops')ya que el tipo anotado del argumento es int. La sugerencia de tipo agregada no provoca 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 los 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:Argument1 to "foo" has incompatible type "str"; expected "int"
(Es posible que necesite instalar mypydesde su administrador de paquetes. No creo que venga con CPython pero parece tener cierto nivel de "oficialidad").
La verificación de tipos de esta manera es diferente de la verificación de tipos en lenguajes compilados de tipo estático. 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 suceda en cada oportunidad. Las verificaciones de tipo explícitas también pueden ser más restrictivas de lo necesario y causar errores innecesarios (por ejemplo, ¿es necesario que el argumento sea exactamente del listtipo o es algo iterable suficiente?).
La ventaja de la verificación explícita de tipos es que puede detectar errores antes y dar mensajes de error más claros que la escritura de pato. Los requisitos exactos de un tipo de pato solo se pueden expresar con documentación externa (es de esperar que sea 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 en el que los tipos se pueden especificar y verificar, pero no hay ningún costo adicional durante la ejecución de código habitual.
El typingpaquete ofrece variables de tipo que se pueden usar en sugerencias de tipo para expresar los comportamientos necesarios sin requerir tipos particulares. Por ejemplo, incluye variables como Iterabley Callablepara sugerencias para especificar la necesidad de cualquier tipo con esos comportamientos.
Si bien las sugerencias de tipo son la forma más pitónica de verificar los tipos, a menudo es aún más pitónico no verificar los tipos en absoluto y confiar en la escritura de pato. Las sugerencias de tipo son relativamente nuevas y el jurado aún no sabe cuándo son la solución más pitónica. Una comparación relativamente poco controvertida pero muy general: las sugerencias de tipo proporcionan una forma de documentación que se puede hacer cumplir, permiten que el código genere errores anteriores y más fáciles de entender, puede detectar errores que no se pueden escribir en el pato y se pueden verificar de forma estática (en un caso inusual sentido, pero todavía está fuera del tiempo de ejecución). Por otro lado, el tipeo de pato ha sido la forma pitónica durante mucho tiempo, no impone la sobrecarga cognitiva del tipeo estático, es menos detallado y aceptará todos los tipos viables y más.
-1: mypy específicamente se llama a sí mismo un "verificador de tipo estático", por lo que no estoy seguro de dónde obtuviste "la verificación de tipo debe hacerse en tiempo de ejecución".
Kevin
@Kevin En retrospectiva, esa fue una digresión innecesaria, pero para profundizar más, las sugerencias de tipo de Python se convierten en datos de tiempo de ejecución y mypyes un módulo de Python que se utiliza importlibpara acceder a esos datos. Si esto es una "verificación de tipo estático" es una pregunta filosófica, pero es diferente de lo que la mayoría esperaría ya que el intérprete de lenguaje normal y la maquinaria de importación están involucrados.
Praxeolítico
44
Eso tampoco es cierto. Se utiliza typed_ast, que a su vez es sólo un clon de AST con características adicionales. ast no importa módulos; los analiza en un árbol de sintaxis abstracta.
Kevin
18
Aquí hay un ejemplo de por qué escribir pato es malo sin saber cuándo es peligroso. Por ejemplo: Aquí está el código Python (posiblemente omitiendo la sangría adecuada), tenga en cuenta que esta situación se puede evitar cuidando las funciones isinstance y issubclassof para asegurarse de que cuando realmente necesite un pato, no obtenga una bomba.
classBomb:def __init__(self):""def talk(self):
self.explode()def explode(self):print"BOOM!, The bomb explodes."classDuck:def __init__(self):""def talk(self):print"I am a duck, I will not blow up if you ask me to talk."classKid:
kids_duck =Nonedef __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()
Incluso con la verificación de tipos, puede crear class EvilDuck(Duck)y anular talk (). O más probablemente, class ChineseCancerDuck(Duck)con un efecto secundario desagradable que no aparece hasta años después. Sería mejor supervisar a tu hijo (y probar a fondo sus juguetes :)
Brett Thomas
36
Las bombas no hablan. No agregue métodos sin sentido y esto no sucederá.
derecha el
77
@Dmitry, esta es la crítica común de Duck Typing: en.wikipedia.org/wiki/Duck_typing#Criticism ... básicamente estás diciendo que cualquier interfaz para la que el lenguaje no impone la semántica es mala. Creo que este es más el enfoque de Java. El punto principal de la escritura de pato de Python es que solo funciona cuando hay una convención comúnmente confirmada sobre lo que significan las interfaces específicas. Por ejemplo, podría descifrar una gran cantidad de código Python al anular el __file__atributo (comúnmente utilizado para identificar objetos similares a archivos) para que signifique algo más.
Dan Lenski
2
Todo esto se reduce a la vieja broma "Doctor, me duele cuando hago esto". ... "Entonces no hagas eso". Insatisfactorio para alguien que está acostumbrado a "si se compila, se ejecuta", pero es por eso que la obsesión por las pruebas surgió del mundo del lenguaje dinámico.
clacke
1
@clacke básicamente, es demasiado costoso imponer tipos en tiempo de ejecución estrictamente porque TODO debe ser un objeto (para mapear de una cadena a cualquier tipo posible), y demasiado conveniente para no tener tipeado porque el tipeado permite técnicas de prototipos realmente poderosas que superan cosas que normalmente son muy difíciles de hacer con interfaces rígidas. Además, cualquier lenguaje estático se enfrenta a un punto en el que necesita crear tipeo de pato a través de bibliotecas dinámicas, evaluación y stringificación, o interfaces, y estas cosas no lo hacen inherentemente malo, solo muy poderoso.
Si bien este enlace puede responder la pregunta, es mejor incluir aquí las partes esenciales de la respuesta y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden volverse inválidas si la página vinculada cambia.
EKons
7
Creo que lo bueno de usar un lenguaje dinámico como Python es que realmente no deberías tener que verificar algo así.
Simplemente llamaría a los métodos requeridos en su objeto y capturarí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 probarlo.
Lo he usado mucho cuando obtengo datos de la web con los urllib2.urlopen()que devuelve un archivo como objeto. Esto a su vez se puede pasar a casi cualquier método que lea de un archivo, ya que implementa el mismo read()método que un archivo real.
Pero estoy seguro de que hay un momento y lugar para usar isinstance(), de lo contrario, probablemente no estaría allí :)
Gracias, este es el código secreto que quería cuando lo mostraba como comentario para el usuario. Me tomó demasiado tiempo encontrar esto ...
Aaron D. Marasco
5
A Hugo:
Probablemente quieras decir en listlugar dearray , pero eso apunta al problema completo con la verificación de tipos: no quieres saber si el objeto en cuestión es una lista, quieres saber si es algún tipo de secuencia o si es un solo objeto. Intenta usarlo como una secuencia.
Supongamos que desea agregar el objeto a una secuencia existente, o si es una secuencia de objetos, agréguelos todos
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 valor único o una secuencia, lo que facilita las cosas. No es difícil poner un [ ]valor único alrededor de usted cuando lo pasa si es necesario.
(Aunque esto puede causar errores con las cadenas, ya que se ven como (son) secuencias).
Respuestas:
Para verificar si
o
es una instanciastr
o alguna subclase destr
, use isinstance (esta sería la forma "canónica"):Para verificar si el tipo de
o
es exactamentestr
(excluir subclases):Lo siguiente también funciona y puede ser útil en algunos casos:
Consulte Funciones incorporadas en la Referencia de la biblioteca de Python para obtener información relevante.
Una nota más: en este caso, si está usando Python 2, es posible que desee usar:
porque esto también capturará cadenas Unicode (
unicode
no es una subclase destr
; ambasstr
yunicode
son subclases debasestring
). Tenga en cuenta quebasestring
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
sio
es una instancia de cualquier subclase de cualquiera de(str, unicode)
:fuente
type(a) is Object
entonces no es cierto también esoisinstance(a, Object)
. Sin embargo, sitype(a) is SubClassOfObject
, entoncestype(a) is Object == False
, peroisinstance(a, Object) == True
. ¿Derecha?a is b
significa que ayb son exactamente lo mismo, es decir, referencias a la misma entidad en la memoria. Entonces,a
yb
tendría que ser exactamente la misma clase, no subclases, como conisinstance()
. Ver por ejemplo stackoverflow.com/a/133024/1072212La forma más pitónica de verificar el tipo de un objeto es ... no verificarlo.
Dado que Python alienta a Duck Typing , solo debe
try...except
usar los métodos del objeto de la forma en que desea usarlos. Entonces, si su función está buscando un objeto de archivo grabable, no verifique que sea una subclase defile
, ¡solo intente usar su.write()
método!Por supuesto, a veces estas agradables abstracciones se descomponen y
isinstance(obj, cls)
es lo que necesitas. Pero use con moderación.fuente
if hasattr(ob, "write") and callable(ob.write):
O guardar algún acceso dict ...func = getattr(ob, "write", None)
if callable(func): ...
hasattr
solo suprime un AttributeError - Ver: docs.python.org/3.4/library/functions.html#hasattrisinstance(o, str)
regresaráTrue
sio
esstr
o es de un tipo que hereda destr
.type(o) is str
volveráTrue
si y solo sio
es un str. VolveráFalse
sio
es de un tipo que hereda destr
.fuente
isinstance
ytype(var) == type('')
no está clara.Después de hacer y responder la pregunta, se agregaron sugerencias de tipo a Python . Las sugerencias de tipo en Python permiten que se verifiquen los tipos, pero de una manera muy diferente a los lenguajes estáticos. 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 que se verifiquen los tipos. Ejemplo de sintaxis de sugerencia de tipo:
En este caso, queremos que se active un error
foo('oops')
ya que el tipo anotado del argumento esint
. La sugerencia de tipo agregada no provoca 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 los errores de tipo.Uno de estos otros programas que se pueden usar para encontrar el error de tipo es
mypy
:(Es posible que necesite instalar
mypy
desde su administrador de paquetes. No creo que venga con CPython pero parece tener cierto nivel de "oficialidad").La verificación de tipos de esta manera es diferente de la verificación de tipos en lenguajes compilados de tipo estático. 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 suceda en cada oportunidad. Las verificaciones de tipo explícitas también pueden ser más restrictivas de lo necesario y causar errores innecesarios (por ejemplo, ¿es necesario que el argumento sea exactamente del
list
tipo o es algo iterable suficiente?).La ventaja de la verificación explícita de tipos es que puede detectar errores antes y dar mensajes de error más claros que la escritura de pato. Los requisitos exactos de un tipo de pato solo se pueden expresar con documentación externa (es de esperar que sea 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 en el que los tipos se pueden especificar y verificar, pero no hay ningún costo adicional durante la ejecución de código habitual.
El
typing
paquete ofrece variables de tipo que se pueden usar en sugerencias de tipo para expresar los comportamientos necesarios sin requerir tipos particulares. Por ejemplo, incluye variables comoIterable
yCallable
para sugerencias para especificar la necesidad de cualquier tipo con esos comportamientos.Si bien las sugerencias de tipo son la forma más pitónica de verificar los tipos, a menudo es aún más pitónico no verificar los tipos en absoluto y confiar en la escritura de pato. Las sugerencias de tipo son relativamente nuevas y el jurado aún no sabe cuándo son la solución más pitónica. Una comparación relativamente poco controvertida pero muy general: las sugerencias de tipo proporcionan una forma de documentación que se puede hacer cumplir, permiten que el código genere errores anteriores y más fáciles de entender, puede detectar errores que no se pueden escribir en el pato y se pueden verificar de forma estática (en un caso inusual sentido, pero todavía está fuera del tiempo de ejecución). Por otro lado, el tipeo de pato ha sido la forma pitónica durante mucho tiempo, no impone la sobrecarga cognitiva del tipeo estático, es menos detallado y aceptará todos los tipos viables y más.
fuente
mypy
es un módulo de Python que se utilizaimportlib
para acceder a esos datos. Si esto es una "verificación de tipo estático" es una pregunta filosófica, pero es diferente de lo que la mayoría esperaría ya que el intérprete de lenguaje normal y la maquinaria de importación están involucrados.Aquí hay un ejemplo de por qué escribir pato es malo sin saber cuándo es peligroso. Por ejemplo: Aquí está el código Python (posiblemente omitiendo la sangría adecuada), tenga en cuenta que esta situación se puede evitar cuidando las funciones isinstance y issubclassof para asegurarse de que cuando realmente necesite un pato, no obtenga una bomba.
fuente
class EvilDuck(Duck)
y anular talk (). O más probablemente,class ChineseCancerDuck(Duck)
con un efecto secundario desagradable que no aparece hasta años después. Sería mejor supervisar a tu hijo (y probar a fondo sus juguetes :)__file__
atributo (comúnmente utilizado para identificar objetos similares a archivos) para que signifique algo más.Enlace a documentos
fuente
Creo que lo bueno de usar un lenguaje dinámico como Python es que realmente no deberías tener que verificar algo así.
Simplemente llamaría a los métodos requeridos en su objeto y capturarí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 probarlo.Lo he usado mucho cuando obtengo datos de la web con los
urllib2.urlopen()
que devuelve un archivo como objeto. Esto a su vez se puede pasar a casi cualquier método que lea de un archivo, ya que implementa el mismoread()
método que un archivo real.Pero estoy seguro de que hay un momento y lugar para usar
isinstance()
, de lo contrario, probablemente no estaría allí :)fuente
Para validaciones de tipos más complejas, me gusta el enfoque de validación de typeguard basado en anotaciones de sugerencias de tipo python:
Puede realizar validaciones muy complejas de una manera muy limpia y legible.
fuente
Puede verificar el tipo de una variable usando __name__ de un tipo.
Ex:
fuente
A Hugo:
Probablemente quieras decir en
list
lugar dearray
, pero eso apunta al problema completo con la verificación de tipos: no quieres saber si el objeto en cuestión es una lista, quieres saber si es algún tipo de secuencia o si es un solo objeto. Intenta usarlo como una secuencia.Supongamos que desea agregar el objeto a una secuencia existente, o si es una secuencia de objetos, agréguelos todos
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 valor único o una secuencia, lo que facilita las cosas. No es difícil poner un
[ ]
valor único alrededor de usted cuando lo pasa si es necesario.(Aunque esto puede causar errores con las cadenas, ya que se ven como (son) secuencias).
fuente
Una forma simple de verificar el tipo es compararlo con algo cuyo tipo conoces.
fuente
Creo que la mejor manera es escribir bien sus variables. Puede hacer esto utilizando la biblioteca "escribiendo".
Ejemplo:
from typing import NewType UserId = NewType ('UserId', int) some_id = UserId (524313
) `Ver https://docs.python.org/3/library/typing.html
fuente
Puede verificar con la línea a continuación para verificar qué tipo de carácter es el valor dado:
fuente