2010-06-24 20 views
10

Tengo un método que acepta un parámetro que puede ser de varios tipos, y tiene que hacer una cosa u otra dependiendo del tipo, pero si compruebo el tipo de dicho parámetro, no obtengo el tipo 'real' , Siempre recibo <type 'instance'>, y eso es un desastre con mis comparaciones.¿Por qué el tipo (classInstance) devuelve 'instancia'?

que tienen algo así como:

from classes import Class1 
from classes import Class2 
# Both classes are declared in the same file. 
# I don't know if that can be a problem   # 
# ... # 
def foo(parameter) 
    if (type(parameter) == type(Class1()): 
    # ... # 
    elif (type(parameter) == type(Class2()): 
    # ... # 

Y como type(parameter) vuelve <type 'instance'> y type(Class1()) es <type 'instance'> así, resulta que incluso si el parámetro es una instancia de clase 2, que va en la primera comparación. ..

Por cierto, str(parameter.__class__) muestra correctamente classes.Class1. Supongo que siempre podría usar eso, pero me gustaría entender qué está pasando ... He hecho décimas comparaciones como esta y todas funcionaron correctamente ...

Gracias! :)

Respuesta

15

Las clases antiguas hacen eso. Derive sus clases de object en sus definiciones.

+0

Wooo ... Eso funciona! :) Ahora voy a tratar de averiguar "por qué" ...: D – BorrajaX

+0

Tiene que ver con el hecho de que las clases de nuevo estilo tienen más metadatos, incluyendo las cosas que 'tipo()' toca. –

+0

Thx otra vez, estaba leyendo esto: http://www.cafepy.com/article/python_types_and_objects/python_types_and_objects.html Y yo como que (especie de) pensé que algo así tenía que ser la razón – BorrajaX

10

se debe utilizar realmente isinstance:

In [26]: def foo(param): 
    ....:  print type(param) 
    ....:  print isinstance(param, Class1) 
    ....: 

In [27]: foo(x) 
<type 'instance'> 
True 

tipo es mejor para este tipo incorporado.

+0

Woo! Gracias por la respuesta muy rápido ... que consideró que, pero luego leí esto: http://www.canonical.org/~kragen/isinstance/ Y me acobardó ...: S Aunque debo decir que, por otro lado, 'isinstance' my sea adecuado para mis necesidades ... – BorrajaX

+2

'isinstance' por lo general es preferible a la comprobación directa de' type() ', y definitivamente la forma de comprobación de tipo que está usando donde crea una instancia de' Class1() 'para cada comprobación no es deseable. Sin embargo, lo que ese artículo está diciendo es que, en muchos casos, verificar los tipos * en absoluto * (cualquiera que sea el método que use para eso) es un signo de mala práctica de codificación. IMO el artículo es inútilmente religioso y todavía hay usos válidos para la verificación de tipos, pero si estás haciendo 'decenas' de controles en contra de tus propios tipos definidos, suena como un posible olor a código 'no lo suficientemente orientado a objetos'. – bobince

+0

Puede ver claramente en el código Ops por qué hacer una verificación de tipo significa que * no * está haciendo OOP: Cualquier código que vendría después de 'if isinstace (obj, Cls)' debería estar en un método de Cls. Puede sonar religioso, pero si quieres usar OOP (no es necesario) entonces tienes que obtener * al menos ese * derecho. –

9

El hecho de que type(x) devuelve el mismo tipo de objeto para todas las instancias x del legado, también conocido como de estilo antiguo, clases, es uno de los muchos defectos irritantes de ese tipo de clases - por desgracia tienen que quedarse (y que sea el predeterminado para una clase sin base) en Python 2.* por razones de compatibilidad con versiones anteriores.

Sin embargo, no utilice las clases antiguas a menos que se vea obligado a mantener un montón de código anterior (sin un buen conjunto de pruebas para darle la confianza de intentar cambiar las clases o clases). Cuando una clase no tiene bases "naturales", la subclases de object en lugar de nada. Como alternativa, el módulo, en la parte superior, puede fijar

__metaclass__ = type 

que cambia el valor por defecto de las enrevesada, clases legado de estilo antiguo, a los brillantes brillantes los de nuevo cuño - mientras que heredar explícitamente de object se prefiere normalmente ("explícita es mejor que implícita"), la configuración de módulo global de __metaclass__ puede parecer "menos invasiva" a los módulos antiguos existentes en los que se cambia de clases antiguas a nuevas, por lo que se ofrece como una posibilidad.

+0

¡Gracias! ¡Buena respuesta también! Ya había usado el propuesto por Ignacio. pero bueno ... al final, si mi entendimiento es correcto, son bastante similares, ¿verdad? – BorrajaX

+0

@Borrajax, el resultado final de heredar explícitamente de 'objeto' frente a no heredar y tener un módulo-global' __metaclass __ = tipo' es exactamente el mismo: estilos muy diferentes, resultados indistinguibles. –

Cuestiones relacionadas