payton - ¿Cuál es la mejor manera(idiomática) de verificar el tipo de una variable de Python?
python de (10)
¿Qué sucede si alguien pasa una cadena Unicode a su función? O una clase derivada de dict? ¿O una clase que implementa una interfaz similar a un dict? El siguiente código cubre los dos primeros casos. Si está utilizando Python 2.6, es posible que desee utilizar collections.Mapping
dict
lugar de dict
según el ABC PEP .
def value_list(x):
if isinstance(x, dict):
return list(set(x.values()))
elif isinstance(x, basestring):
return [x]
else:
return None
Esta pregunta ya tiene una respuesta aquí:
Necesito saber si una variable en Python es una cadena o un dict. ¿Hay algún problema con el siguiente código?
if type(x) == type(str()):
do_something_with_a_string(x)
elif type(x) == type(dict()):
do_somethting_with_a_dict(x)
else:
raise ValueError
Actualización : acepté la respuesta del usuario (aunque cambiaré de opinión si alguien explica por isinstance
es preferible el isinstance
sobre el type(x) is
).
Pero gracias a nakedfanatic por recordarme que a menudo es más limpio usar un dict (como una declaración de caso) que una serie if / elif / else.
Déjame explicarte en mi caso de uso. Si una variable es una cadena, necesito ponerla en una lista. Si es un dictado, necesito una lista de los valores únicos. Esto es lo que se me ocurrió:
def value_list(x):
cases = {str: lambda t: [t],
dict: lambda t: list(set(t.values()))}
try:
return cases[type(x)](x)
except KeyError:
return None
Si se prefiere isinstance
, ¿cómo escribiría esta función value_list()
?
Creo que optaré por el enfoque de tipeo de pato: "si camina como un pato, grita como un pato, es un pato". De esta manera no tendrá que preocuparse si la cadena es unicode o ascii.
Esto es lo que haré:
In [53]: s=''somestring''
In [54]: u=u''someunicodestring''
In [55]: d={}
In [56]: for each in s,u,d:
if hasattr(each, ''keys''):
print list(set(each.values()))
elif hasattr(each, ''lower''):
print [each]
else:
print "error"
....:
....:
[''somestring'']
[u''someunicodestring'']
[]
Los expertos aquí son bienvenidos para comentar sobre este tipo de uso del patito, lo he estado usando pero últimamente me presentaron el concepto exacto detrás de él y estoy muy entusiasmado con él. Así que me gustaría saber si eso es una exageración que hacer.
Creo que podría ser preferible hacer realmente
if isinstance(x, str):
do_something_with_a_string(x)
elif isinstance(x, dict):
do_somethting_with_a_dict(x)
else:
raise ValueError
2 Los formularios alternativos, dependiendo de su código, uno u otro, probablemente se consideren mejores que eso incluso. Una es no mirar antes de saltar.
try:
one, two = tupleOrValue
except TypeError:
one = tupleOrValue
two = None
El otro enfoque es de Guido y es una forma de sobrecarga de funciones que deja su código más abierto.
Es posible que desee revisar typecheck. http://pypi.python.org/pypi/typecheck
Módulo de comprobación de tipo para Python
Este paquete proporciona potentes funciones de comprobación de tipos en tiempo de ejecución para funciones, métodos y generadores de Python. Sin requerir un preprocesador personalizado ni alteraciones en el lenguaje, el paquete typecheck permite a los programadores e ingenieros de control de calidad realizar afirmaciones precisas sobre la entrada y salida de su código.
Eso debería funcionar, así que no, no hay nada de malo en su código. Sin embargo, también se podría hacer con un dict:
{type(str()): do_something_with_a_string,
type(dict()): do_something_with_a_dict}.get(type(x), errorhandler)()
Un poco más conciso y pitónico, ¿no te parece?
Editar ... Siguiendo los consejos de Avisser, el código también funciona así, y se ve mejor:
{str: do_something_with_a_string,
dict: do_something_with_a_dict}.get(type(x), errorhandler)()
He estado usando un enfoque diferente:
from inspect import getmro
if (type([]) in getmro(obj.__class__)):
# This is a list, or a subclass of...
elif (type{}) in getmro(obj.__class__)):
# This one is a dict, or ...
No puedo recordar por qué usé esto en lugar de la instancia, aunque ...
Isinstance es preferible al tipo porque también se evalúa como Verdadero cuando se compara una instancia de objeto con su superclase, lo que básicamente significa que nunca tendrá que hacer caso especial de su antiguo código para usarlo con las subclases dict o str.
Por ejemplo:
>>> class a_dict(dict):
... pass
...
>>> type(a_dict()) == type(dict())
False
>>> isinstance(a_dict(), dict)
True
>>>
Por supuesto, puede haber situaciones en las que no querría este comportamiento, pero esas son –hoyas– mucho menos comunes que las situaciones en las que sí lo desea.
los tipos incorporados en Python tienen nombres incorporados:
>>> s = "hallo"
>>> type(s) is str
True
>>> s = {}
>>> type(s) is dict
True
Por cierto, tenga en cuenta el operador. Sin embargo, la verificación de tipo (si desea llamarlo así) se realiza generalmente envolviendo una prueba específica del tipo en una cláusula de prueba de excepción, ya que no es tanto el tipo de variable que es importante, sino si puede hacer un cierto algo con eso o no
*sigh*
No, no es necesario revisar los argumentos en Python. Nunca es necesario.
Si su código acepta una cadena o un objeto dict, su diseño se rompe.
Eso se debe al hecho de que si no conoce el tipo de objeto en su propio programa, entonces ya está haciendo algo mal.
La comprobación de tipos daña la reutilización del código y reduce el rendimiento. Tener una función que realiza diferentes cosas dependiendo del tipo de objeto pasado es propenso a errores y tiene un comportamiento más difícil de entender y mantener.
Tienes las siguientes opciones de saner:
1) Haga una función de unique_values
que convierta dects en listas únicas de valores:
def unique_values(some_dict):
return list(set(some_dict.values()))
Haz que tu función asuma que el argumento pasado es siempre una lista. De esa manera, si necesita pasar una cadena a la función, simplemente haga lo siguiente:
myfunction([some_string])
Si necesitas pasar un dictado, lo haces:
myfunction(unique_values(some_dict))
Esa es su mejor opción, es limpia, fácil de entender y mantener. Cualquiera que lea el código de inmediato comprende lo que está sucediendo, y usted no tiene que revisar a máquina.
2) Haga dos funciones, una que acepte listas de cadenas y otra que acepte dictados. Puede hacer una llamada a la otra internamente, de la manera más conveniente ( myfunction_dict
puede crear una lista de cadenas y llamar a myfunction_list
).
En cualquier caso, no hay que revisar . Es completamente innecesario y solo tiene desventajas. Refactorice su código en lugar de una manera que no necesite revisar. Solo obtienes beneficios al hacerlo, tanto a corto como a largo plazo.
type(dict())
dice "crea un nuevo dict, y luego descubre cuál es su tipo". Es más rápido decir simplemente "dict". Pero si solo quiere marcar el tipo, una forma más idiomática es la isinstance(x, dict)
.
Tenga en cuenta que isinstance
también incluye subclases (gracias Dustin ):
class D(dict):
pass
d = D()
print("type(d) is dict", type(d) is dict) # -> False
print("isinstance (d, dict)", isinstance(d, dict)) # -> True