class A(object):
pass
class B(A):
pass
o = object()
a = A()
b = B()
Meskipun saya bisa berubah a.__class__
, saya tidak bisa melakukan hal yang sama o.__class__
(itu melempar TypeError
kesalahan). Mengapa?
Sebagai contoh:
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)
Saya tahu ini umumnya bukan ide yang baik, karena dapat menyebabkan perilaku yang sangat aneh jika ditangani dengan tidak benar. Hanya demi rasa penasaran.
python
python-3.x
Riccardo Bucco
sumber
sumber
Jawaban:
CPython memiliki komentar di Objects / typeobject.c pada topik ini:
Penjelasan:
CPython menyimpan objek dalam dua cara:
Informasi dari komentar di Sertakan / objek.h .
Ketika Anda mencoba untuk menetapkan nilai baru
some_obj.__class__
,object_set_class
fungsinya dipanggil. Itu diwarisi dari PyBaseObject_Type , lihat/* tp_getset */
bidang. Fungsi ini memeriksa : dapatkah tipe baru menggantikan tipe lamasome_obj
?Ambil contoh Anda:
Kasus pertama:
Jenis
a
objek adalahA
, tipe tumpukan, karena dialokasikan secara dinamis. SertaB
. Thea
tipe 's berubah tanpa masalah.Kasus kedua:
Tipe
o
adalah tipe bawaanobject
(PyBaseObject_Type
). Ini bukan tipe heap, jadiTypeError
dinaikkan:sumber
Anda hanya dapat mengubah
__class__
ke tipe lain yang memiliki tata letak internal (C) yang sama . Runtime bahkan tidak tahu tata letak itu kecuali tipe itu sendiri secara dinamis dialokasikan ("tipe tumpukan"), jadi itu adalah kondisi yang diperlukan yang mengecualikan tipe bawaan sebagai sumber atau tujuan. Anda juga harus memiliki set yang sama__slots__
dengan nama yang sama.sumber