class A(object):
pass
class B(A):
pass
o = object()
a = A()
b = B()
Si bien puedo cambiar a.__class__, no puedo hacer lo mismo con o.__class__(arroja un TypeErrorerror). ¿Por qué?
Por ejemplo:
isinstance(a, A) # True
isinstance(a, B) # False
a.__class__ = B
isinstance(a, A) # True
isinstance(a, B) # True
isinstance(o, object) # True
isinstance(o, A) # False
o.__class__ = A # This fails and throws a TypeError
# isinstance(o, object)
# isinstance(o, A)
Sé que esto generalmente no es una buena idea, ya que puede conducir a un comportamiento muy extraño si se maneja incorrectamente. Es solo por curiosidad.
python
python-3.x
Riccardo Bucco
fuente
fuente

Respuestas:
CPython tiene un comentario en Objects / typeobject.c sobre este tema:
Explicación:
CPython almacena objetos de dos maneras:
Información del comentario en Incluir / objeto.h .
Cuando intenta establecer un nuevo valor
some_obj.__class__,object_set_classse llama a la función. Se hereda de PyBaseObject_Type , ver/* tp_getset */campo. Esta función comprueba : ¿puede el nuevo tipo reemplazar al antiguosome_obj?Toma tu ejemplo:
Primer caso:
El tipo de
aobjeto esA, el tipo de montón, porque se asigna dinámicamente. Así como elB. Elatipo de 's se cambia sin problema.Segundo caso:
El tipo de
oes el tipo incorporadoobject(PyBaseObject_Type). No es de tipo montón, por lo queTypeErrorse genera:fuente
Solo puede cambiar
__class__a otro tipo que tenga el mismo diseño interno (C) . El tiempo de ejecución ni siquiera conoce ese diseño a menos que el tipo en sí se asigne dinámicamente (un "tipo de montón"), por lo que es una condición necesaria que excluye los tipos integrados como origen o destino. También debe tener el mismo conjunto de__slots__con los mismos nombres.fuente