class A(object):
pass
class B(A):
pass
o = object()
a = A()
b = B()
Ich kann mich zwar ändern a.__class__
, aber ich kann nicht dasselbe tun o.__class__
(es wird ein TypeError
Fehler ausgegeben). Warum?
Zum Beispiel:
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)
Ich weiß, dass dies im Allgemeinen keine gute Idee ist, da es zu einem sehr seltsamen Verhalten führen kann, wenn es falsch behandelt wird. Es ist nur aus Neugier.
python
python-3.x
Riccardo Bucco
quelle
quelle
Antworten:
CPython hat in Objects / typeobject.c einen Kommentar zu diesem Thema:
Erläuterung:
CPython speichert Objekte auf zwei Arten:
Informationen aus dem Kommentar in Include / object.h .
Wenn Sie versuchen, einen neuen Wert auf festzulegen,
some_obj.__class__
wird dieobject_set_class
Funktion aufgerufen. Es wird von PyBaseObject_Type geerbt , siehe/* tp_getset */
Feld. Diese Funktion prüft : Kann der neue Typ den alten Typ ersetzensome_obj
?Nehmen Sie Ihr Beispiel:
Erster Fall:
Der
a
Objekttyp istA
der Heap-Typ, da er dynamisch zugewiesen wird. Sowie dieB
. Dera
Typ wird problemlos geändert.Zweiter Fall:
Der Typ von
o
ist der integrierte Typobject
(PyBaseObject_Type
). Es ist kein Heap-Typ, daherTypeError
wird das ausgelöst:quelle
Sie können nur
__class__
zu einem anderen Typ wechseln , der dasselbe interne (C) Layout hat . Die Laufzeit kennt dieses Layout nur, wenn der Typ selbst dynamisch zugewiesen wird (ein „Heap-Typ“). Dies ist also eine notwendige Bedingung, die die integrierten Typen als Quelle oder Ziel ausschließt. Sie müssen auch den gleichen Satz__slots__
mit den gleichen Namen haben.quelle