2009-06-29 30 views
35

¿Cuál es la diferencia entre type(obj) y obj.__class__? ¿Existe alguna posibilidad de type(obj) is not obj.__class__?Diferencia entre tipo (obj) y obj .__ class__

Quiero escribir una función que funcione genéricamente en los objetos suministrados, utilizando un valor predeterminado de 1 en el mismo tipo que otro parámetro. ¿Qué variación, n. ° 1 o n. ° 2 a continuación, va a hacer lo correcto.

def f(a, b=None): 
    if b is None: 
    b = type(a)(1) # #1 
    b = a.__class__(1) # #2 

Respuesta

12

type(obj) y type.__class__ no se comportan de la misma para las clases de estilo antiguo:

>>> class a(object): 
...  pass 
... 
>>> class b(a): 
...  pass 
... 
>>> class c: 
...  pass 
... 
>>> ai=a() 
>>> bi=b() 
>>> ci=c() 
>>> type(ai) is ai.__class__ 
True 
>>> type(bi) is bi.__class__ 
True 
>>> type(ci) is ci.__class__ 
False 
+7

La ironía más grande es que el comentario de yairchu ahora tiene el mismo problema ya que cambiaron el formato ...: P –

+10

No estaría de más mostrar * cómo * se comportan de manera diferente, y tal vez también * por qué *. Solo decir * cuando * se comportan de manera diferente suena una respuesta floja, incluso si es correcta. – MestreLion

+1

vale mencionar que este es solo el problema en Python 2. En Python 3, las tres expresiones serán True. – Bob

30

clases de estilo antiguo son el problema, suspiro:

>>> class old: pass 
... 
>>> x=old() 
>>> type(x) 
<type 'instance'> 
>>> x.__class__ 
<class __main__.old at 0x6a150> 
>>> 

No es un problema en Python 3, ya que todas las clases son de nuevo cuño ahora ;-).

En Python 2, es una clase única de nuevo estilo si se hereda de otra clase de nuevo estilo (incluyendo object y los diversos tipos incorporados como dict, list, set, ...) o de forma implícita o explícita establece __metaclass__ a type.

+3

Es Python 3 veces, que * debería * usamos? –

+2

Si su código sigue las mejores prácticas según lo descrito por Alex, 'type()' sería preferible. En Python 3, siempre sigue las mejores prácticas, así que use type() en Python 3. –

+0

@AaronHall ¿Sería correcto para mí suponer que usar 'type()' también es preferible a '__class__' si estoy escribiendo Python 2 código donde sé que solo se llamará con instancias de clases de nuevo estilo? – kasperd

30

Esta es una vieja pregunta, pero ninguna de las respuestas parece mencionar que. en el caso general, se ES posible para una clase de nuevo estilo para tener valores diferentes para type(instance) y instance.__class__:

class ClassA(object): 
    def display(self): 
     print("ClassA") 

class ClassB(object): 
    __class__ = ClassA 

    def display(self): 
     print("ClassB") 

instance = ClassB() 

print(type(instance)) 
print(instance.__class__) 
instance.display() 

Salida:

<class '__main__.ClassB'> 
<class '__main__.ClassA'> 
ClassB 

La razón es que ClassB es reemplazar el __class__ descriptor, sin embargo, el campo de tipo interno en el objeto no se cambia. type(instance) lee directamente desde ese campo de tipo, por lo que devuelve el valor correcto, mientras que instance.__class__ hace referencia al nuevo descriptor que reemplaza el descriptor original proporcionado por Python, que lee el campo de tipo interno. En lugar de leer ese campo de tipo interno, devuelve un valor codificado.

+10

_Caveat lector_: esto debe tomarse como un ejemplo de por qué debe evitar anular '__class__'! Puede causar código en la línea que usa '__class__' para romper. –

+0

También se ve afectado por '__getattribute__', que intercepta la solicitud de' OBJ .__ class__' pero no para 'type (OBJ)'. – kdb

Cuestiones relacionadas