class A(object):
pass
class B(A):
pass
o = object()
a = A()
b = B()
Bien que je puisse changer a.__class__
, je ne peux pas faire de même avec o.__class__
(cela génère une TypeError
erreur). Pourquoi?
Par exemple:
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)
Je sais que ce n'est généralement pas une bonne idée, car cela peut conduire à un comportement très étrange s'il est mal géré. C'est juste pour la curiosité.
python
python-3.x
Riccardo Bucco
la source
la source
Réponses:
CPython a un commentaire dans Objects / typeobject.c sur ce sujet:
Explication:
CPython stocke les objets de deux manières:
Informations du commentaire dans Include / object.h .
Lorsque vous essayez de définir une nouvelle valeur sur
some_obj.__class__
, laobject_set_class
fonction est appelée. Il est hérité de PyBaseObject_Type , voir/* tp_getset */
champ. Cette fonction vérifie : le nouveau type peut-il remplacer l'ancien type danssome_obj
?Prenez votre exemple:
Premier cas:
Le type d'
a
objet estA
le type de segment, car il est alloué dynamiquement. Ainsi que leB
. Lea
type de est modifié sans problème.Deuxième cas:
Le type de
o
est le type intégréobject
(PyBaseObject_Type
). Ce n'est pas du type tas, donc leTypeError
est levé:la source
Vous ne pouvez changer
__class__
à un autre type qui a la même interne (C) mise en page . Le runtime ne connaît même pas cette disposition à moins que le type lui-même ne soit alloué dynamiquement (un «type de segment»), c'est donc une condition nécessaire qui exclut les types intégrés en tant que source ou destination. Vous devez également avoir le même ensemble de__slots__
avec les mêmes noms.la source