class A(object):
pass
class B(A):
pass
o = object()
a = A()
b = B()
Embora eu possa mudar a.__class__
, não posso fazer o mesmo o.__class__
(gera um TypeError
erro). Por quê?
Por exemplo:
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)
Sei que isso geralmente não é uma boa ideia, pois pode levar a um comportamento muito estranho se for tratado incorretamente. É apenas por uma questão de curiosidade.
python
python-3.x
Riccardo Bucco
fonte
fonte
Respostas:
O CPython tem um comentário em Objetos / typeobject.c sobre este tópico:
Explicação:
O CPython armazena objetos de duas maneiras:
Informações do comentário em Incluir / objeto.h .
Quando você está tentando definir um novo valor para
some_obj.__class__
, aobject_set_class
função é chamada. É herdado de PyBaseObject_Type , veja o/* tp_getset */
campo. Esta função verifica : o novo tipo pode substituir o tipo antigosome_obj
?Veja o seu exemplo:
Primeiro caso:
O tipo de
a
objeto éA
o tipo de heap, porque é alocado dinamicamente. Bem como oB
. Oa
tipo do é alterado sem problemas.Segundo caso:
O tipo de
o
é o tipo internoobject
(PyBaseObject_Type
). Não é do tipo heap, então oTypeError
é gerado:fonte
Você só pode mudar
__class__
para outro tipo que tenha o mesmo layout interno (C) . O tempo de execução nem conhece esse layout, a menos que o próprio tipo seja alocado dinamicamente (um “tipo de heap”), portanto, é uma condição necessária que exclui os tipos internos como origem ou destino. Você também precisa ter o mesmo conjunto de__slots__
nomes iguais.fonte