¿Cuál es la mejor manera (idiomático) para comprobar el tipo de una variable de Python? [duplicar]

StackOverflow https://stackoverflow.com/questions/378927

  •  22-08-2019
  •  | 
  •  

Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Necesito saber si una variable en Python es una cadena o un diccionario. ¿Hay algo malo 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

Actualizar . Acepté la respuesta de avisser (aunque voy a cambiar de opinión si alguien explica por qué se prefiere sobre isinstance type(x) is)

Sin embargo, gracias a nakedfanatic por recordarme que a menudo es más limpio de usar un diccionario (como una declaración de caso) de una elif / serie si / else.

Permítanme desarrollar en mi caso de uso. Si una variable es una cadena, tengo que ponerlo en una lista. Si se trata de un diccionario, necesito una lista de los valores únicos. Esto es lo que 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 esta función value_list()?

¿Fue útil?

Solución

¿Qué pasa 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 dict? Siguiente código abarca dos primeros casos. Si está utilizando Python 2.6 es posible que desee utilizar collections.Mapping vez 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

Otros consejos

type(dict()) dice "hacer una nueva dict, y luego averiguar lo que su tipo es". Es más rápido que decir simplemente "dict". Pero si sólo quiere comprobar el tipo, de una manera más idiomática es isinstance(x, dict).

Tenga en cuenta, que también incluye isinstance 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

Los tipos incorporados en Python han construido en los nombres:

>>> s = "hallo"
>>> type(s) is str
True
>>> s = {}
>>> type(s) is dict
True

por cierto nota de la es operador. Sin embargo, la comprobación de tipos (si quieres llamarlo así) se hace generalmente envolviendo una prueba de tipo específico en un bloque try-excepción, ya que no es tanto el tipo de la variable que es importante, pero si usted puede hacer una determinada algo con él o no.

isinstance es preferible sobre el tipo, ya que también se evalúa como True cuando se compara una instancia de objeto con su superclase, que básicamente significa que no tendrá que siempre especial de los casos el código antiguo para usarlo con dict o subclases 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 quieres este comportamiento, pero esos son -hopefully- mucho menos comunes que las situaciones en las que usted desee.

Creo que voy a ir a por el enfoque de la tipificación de pato - "si camina como un pato, grazna como un pato, es un pato". De esta manera usted no necesita preocuparse de si la cadena es un Unicode o ASCII.

Esto es lo que voy a hacer:

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 a comentar sobre este tipo de uso de Duck Typing, he estado usando, pero se habían introducido en el concepto exacto detrás de él últimamente y estoy muy emocionada por ello. Así que me gustaría saber si eso es una exageración de hacer.

Yo creo que puede ser preferible hacer realidad

if isinstance(x, str):
    do_something_with_a_string(x)
elif isinstance(x, dict):
    do_somethting_with_a_dict(x)
else:
    raise ValueError

2 formas alternativas en función de su código de uno u otro probablemente se considera mejor que la de equilibrio. Una de ellas 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 el código sea más abierta terminado.

http://www.artima.com/weblogs/viewpost.jsp? hilo = 155514

Eso debería funcionar - así que no, no hay nada malo con su código. Sin embargo, también se podría hacer con un diccionario:

{type(str()): do_something_with_a_string,
 type(dict()): do_something_with_a_dict}.get(type(x), errorhandler)()

Un poco más conciso y Pythonic no te parece?


Editar .. Siguiendo el consejo de Avisser, el código también funciona como este, y se ve mejor:

{str: do_something_with_a_string,
 dict: do_something_with_a_dict}.get(type(x), errorhandler)()

Es posible que desee comprobar hacia fuera typecheck. http://pypi.python.org/pypi/typecheck

módulo de verificación de tipos para Python

Este paquete proporciona potentes instalaciones de verificación de tipos en tiempo de ejecución de las funciones de Python, los métodos y los generadores. Sin necesidad de un preprocesador personalizado o alteraciones en el lenguaje, el paquete typecheck permite a los programadores e ingenieros de control de calidad para hacer afirmaciones precisas acerca de la entrada a, y la salida de, su código.

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é he usado esta vez de isinstance, aunque ...

*sigh*

No, argumentos verificación de tipos en Python no es necesario. Es no necesario.

Si su código acepta una cadena o un objeto dict, su diseño está roto.

Eso viene del hecho de que si usted no sabe ya el tipo de un objeto en su propio programa, entonces usted está haciendo algo que ya está mal.

verificación de tipos duele la reutilización de código y reduce el rendimiento. Tener una función que realiza funciones distintas dependiendo del tipo de objeto pasado es bug-prono y tiene un comportamiento más difícil de entender y mantener.

Existen las siguientes opciones más sanas:

1) Hacer un unique_values función que convierte dicts en las listas únicas de valores:

def unique_values(some_dict):
    return list(set(some_dict.values()))

Haga su función asume el argumento pasado es siempre una lista. De esa manera, si tiene que pasar una cadena a la función, que acaba de hacer:

myfunction([some_string])

Si tiene que pasar un diccionario, que hace:

myfunction(unique_values(some_dict))

Esa es su mejor opción, es limpio, fácil de entender y mantener. Nadie la lectura del código immediatelly entiende lo que está sucediendo, y que no tiene a typecheck.

2) Hacer dos funciones, una que acepta listas de cadenas y uno que acepta dicts. Puede hacer una llamada, los otros internos, de la forma más conveniente forma (myfunction_dict puede crear una lista de cadenas y llamar a myfunction_list).

En cualquier caso, no typecheck . Es completamente innecesario y sólo tiene desventajas. Refactorizar su código en lugar de una manera que no es necesario typecheck. Sólo se tiene beneficios al hacerlo, tanto en el corto y largo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top