CPython memiliki komentar di Objects / typeobject.c pada topik ini:
Dalam versi CPython sebelum 3.5, kode di
compatible_for_assignmenttidak diatur untuk memeriksa dengan benar untuk memori layout / slot / dll kompatibilitas untuk kelas non-HEAPTYPE, jadi kami hanya menolak __class__penugasan dalam hal apa pun yang bukan HEAPTYPE -> HEAPTYPE.
Selama siklus pengembangan 3,5, kami memperbaiki kode
compatible_for_assignmentuntuk mengecek kompatibilitas antara tipe yang sewenang-wenang, dan mulai memungkinkan __class__penugasan dalam semua kasus di mana tipe lama dan baru sebenarnya memiliki slot dan tata letak memori yang kompatibel (terlepas dari apakah mereka diimplementasikan sebagai HEAPTYPEs atau tidak).
Namun, sebelum 3.5 dirilis, kami menemukan bahwa ini menyebabkan masalah dengan tipe yang tidak dapat diubah seperti int, di mana penerjemah menganggap mereka tidak dapat diubah dan menginternir beberapa nilai. Sebelumnya ini bukan masalah, karena mereka benar-benar tidak dapat diubah - khususnya, semua jenis di mana penerjemah menerapkan trik magang ini juga dialokasikan secara statis, sehingga aturan HEAPTYPE lama "secara tidak sengaja" menghentikan mereka dari mengizinkan __class__penugasan. Tetapi dengan perubahan pada __class__tugas, kami mulai mengizinkan kode seperti
class MyInt(int):
# ...
# Modifies the type of *all* instances of 1 in the whole program,
# including future instances (!), because the 1 object is interned.
(1).__class__ = MyInt
(lihat https://bugs.python.org/issue24912 ).
Secara teori, perbaikan yang tepat adalah mengidentifikasi kelas mana yang bergantung pada invarian ini dan entah bagaimana melarang __class__tugas hanya untuk mereka, mungkin melalui beberapa mekanisme seperti bendera Py_TPFLAGS_IMMUTABLE baru (pendekatan "daftar hitam"). Namun dalam praktiknya, karena masalah ini tidak diketahui di akhir siklus 3.5 RC, kami mengambil pendekatan konservatif dan mengembalikan pemeriksaan HEAPTYPE-> HEAPTYPE yang sama dengan yang dulu kami miliki, plus "daftar putih". Untuk saat ini, daftar putih hanya terdiri dari subtipe ModuleType, karena ini adalah kasus yang memotivasi patch pada awalnya - lihat https://bugs.python.org/issue22986 - dan karena objek modul dapat diubah, kita dapat memastikan bahwa mereka pasti tidak diinternir. Jadi sekarang kita mengizinkan HEAPTYPE-> HEAPTYPE atau
ModuleType subtype -> ModuleType subtype.
Sejauh yang kita ketahui, semua kode di luar pernyataan 'jika' berikut ini akan menangani dengan benar kelas-kelas non-HEAPTYPE, dan pemeriksaan HEAPTYPE hanya diperlukan untuk melindungi subset kelas-kelas non-HEAPTYPE yang telah dibuat oleh juru bahasa dengan asumsi bahwa semua contoh benar-benar abadi.
Penjelasan:
CPython menyimpan objek dalam dua cara:
Objek adalah struktur yang dialokasikan pada heap. Aturan khusus berlaku untuk penggunaan objek untuk memastikan mereka dikumpulkan dengan benar. Objek tidak pernah dialokasikan secara statis atau di stack; mereka harus diakses melalui makro khusus dan fungsi saja. (Tipe objek adalah pengecualian dari aturan pertama; tipe standar diwakili oleh objek tipe yang diinisialisasi secara statis, meskipun bekerja pada tipe / kelas unifikasi untuk Python 2.2 memungkinkan untuk memiliki objek tipe heap-dialokasikan juga).
Informasi dari komentar di Sertakan / objek.h .
Ketika Anda mencoba untuk menetapkan nilai baru some_obj.__class__, object_set_classfungsinya dipanggil. Itu diwarisi dari PyBaseObject_Type , lihat /* tp_getset */bidang. Fungsi ini memeriksa : dapatkah tipe baru menggantikan tipe lama some_obj?
Ambil contoh Anda:
class A:
pass
class B:
pass
o = object()
a = A()
b = B()
Kasus pertama:
a.__class__ = B
Jenis aobjek adalah A, tipe tumpukan, karena dialokasikan secara dinamis. Serta B. The atipe 's berubah tanpa masalah.
Kasus kedua:
o.__class__ = B
Tipe oadalah tipe bawaan object( PyBaseObject_Type). Ini bukan tipe heap, jadi TypeErrordinaikkan:
TypeError: __class__ assignment only supported for heap types or ModuleType subclasses.