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 TypeError
error). ¿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_class
se 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
a
objeto esA
, el tipo de montón, porque se asigna dinámicamente. Así como elB
. Ela
tipo de 's se cambia sin problema.Segundo caso:
El tipo de
o
es el tipo incorporadoobject
(PyBaseObject_Type
). No es de tipo montón, por lo queTypeError
se 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