Python tiene la función incorporada type y cada instancia también tiene un atributo __class__. En general, creía que devolvían lo mismo. Incluso la documentación de ambos suena similar:

instance.__class__

La clase a la que pertenece una instancia de clase.

Y

type(object)

Con un argumento, devuelve el tipo de un objeto.

Sin embargo, en abc.ABCMeta.__instancecheck__ hay un cheque si son idénticos (ligeramente acortados):

subclass = instance.__class__
subtype = type(instance)
if subtype is subclass:

¿Cuándo no será este el caso? ¿Cuándo type(instance) no es lo mismo que instance.__class__?

9
MSeifert 22 feb. 2017 a las 10:18

2 respuestas

La mejor respuesta

type(instance) y instance.__class__ pueden ser diferentes, incluso con clases de estilo nuevo, como Guido mencionó en PEP 3119:

Además, isinstance(x, B) es equivalente a issubclass(x.__class__, B) or issubclass(type(x), B). (Es posible que type(x) y x.__class__ no sean el mismo objeto, por ejemplo, cuando x es un objeto proxy).

Por ejemplo:

class A:
    pass

class B:
    __class__ = A

b = B()
print(type(b))      # prints <class '__main__.B'>
print(b.__class__)  # prints <class '__main__.A'>
3
Maggyero 18 dic. 2018 a las 18:56

Este es el caso de los objetos de estilo antiguo (heredando de la nada). Dichos objetos no tienen la propiedad __class__. Creo que lo hacen de esta manera para evitar errores. Ejemplo para Python 2.7:

class A:
    pass

class B(object):
    pass

a = A()
b = B()

print(dir(a)) # ['__doc__', '__module__']
print(dir(b)) # ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

print(b.__class__) # <class '__main__.B'>
print(type(b))     # <class '__main__.B'>

#####################
# The intersting part
print(a.__class__) # __main__.A
print(type(a))     # <type 'instance'>


print(B.__class__) # <type 'type'>
print(type(B))     # <type 'type'>

print(type(A))      # <type 'classobj'>
#print(A.__class__) # AttributeError: class A has no attribute '__class__'

Vea esto para más información:

Nota: Las líneas dadas de cpython se cambiaron en 2008 la última vez ( commit), por lo que realmente parece ser una cuestión de compatibilidad o simplemente se olvidaron de ello.

1
Community 23 may. 2017 a las 10:29