tipos - str en python
¿Cuál es la forma canónica de verificar el tipo en Python? (9)
¿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
?
A Hugo:
Probablemente te refieres a la list
lugar de a la array
, pero eso apunta a todo el problema con la comprobació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 una sola objeto. Así que trata de usarlo como una secuencia.
Digamos 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 a menudo se considera que una cadena es 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 poner 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).
Aquí hay un ejemplo de por qué la escritura de pato es malvada 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 de instancia y de subclase 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()
Creo que lo bueno 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 atraparí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.
He usado esto mucho cuando urllib2.urlopen()
datos de la web con urllib2.urlopen()
que devuelve un archivo como objeto. 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()
que 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í :)
Después de que se formuló y respondió la pregunta, se agregaron sugerencias de tipo a Python . Las sugerencias de tipo en Python permiten verificar los tipos, 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 las 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 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 deba instalar mypy
desde su 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 de tipo explícitas también pueden ser más restrictivas de lo necesario y causar errores innecesarios (por ejemplo, ¿el argumento realmente debe ser exactamente del tipo de 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 de 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 sugerencias que especifican 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 no verificar los 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 pitónica. Una comparación relativamente incontrovertida pero muy general: las sugerencias de tipo proporcionan una forma de documentación que se puede aplicar, permite que el código genere errores antes y más fáciles de entender, puede detectar errores que la escritura de pato 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 pitónica durante mucho tiempo, no impone la sobrecarga cognitiva de la tipificación estática, es menos detallada y aceptará todos los tipos viables, y algunos.
La forma más pitónica de verificar el tipo de un objeto es ... no comprobarlo.
Como Python recomienda el uso de 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 compruebe que es una subclase de file
, ¡solo intente usar su método .write()
!
Por supuesto, a veces estas bonitas abstracciones se descomponen y lo que necesitas es la isinstance(obj, cls)
. Pero usar con moderación.
Para verificar si o
es una instancia de str
o cualquier subclase de str
, use isinstance (esta sería la forma "canónica"):
if isinstance(o, str):
Para verificar si el tipo de o
es 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ás usando python 2, es posible que desees usar:
if isinstance(o, basestring):
porque esto también capturará cadenas de 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)):
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)
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 un str. Devolverá false
si o
es de un tipo que hereda de str
. ----
isinstance(o, str)