CPython bir yorum vardır Nesneler / typeobject.c bu konuda:
3.5'ten önceki CPython sürümlerinde, kod,
compatible_for_assignment
HEAPTYPE olmayan sınıflar için bellek düzeni / yuva / vb. Uyumluluğunu doğru bir şekilde kontrol edecek şekilde ayarlanmadı, bu nedenle __class__
HEAPTYPE -> HEAPTYPE olmayan her durumda atamaya izin vermedik.
3.5 geliştirme döngüsü sırasında, compatible_for_assignment
rastgele türler arasındaki uyumluluğu doğru bir şekilde kontrol etmek için kodu düzelttik ve
__class__
eski ve yeni türlerin aslında uyumlu yuvalara ve bellek düzenine sahip oldukları tüm durumlarda atamaya izin vermeye başladık (HEAPTYPE olarak uygulandıklarına bakılmaksızın) ya da değil).
3.5 sürümü yayınlanmadan hemen önce, bunun int gibi değişmez türlerle ilgili sorunlara yol açtığını keşfettik. Eskiden bu bir problem değildi, çünkü gerçekten değişmezlerdi - özellikle, tercümanın bu stajyer hileyi uyguladığı tüm türler de statik olarak tahsis edildi, bu nedenle eski HEAPTYPE kuralları "yanlışlıkla" __class__
atamaya izin vermiyordu . Ancak __class__
atamada yapılan değişikliklerle ,
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
(bkz. https://bugs.python.org/issue24912 ).
Teoride doğru çözüm, hangi sınıfların bu değişmeze bağlı olduğunu tanımlamak ve bir şekilde __class__
sadece onlar için ödeve izin vermemek , belki de yeni bir Py_TPFLAGS_IMMUTABLE bayrağı ("kara listeye alma" yaklaşımı) gibi bir mekanizma aracılığıyla. Ancak pratikte, bu sorun 3.5 RC döngüsünün sonlarında fark edilmediğinden, muhafazakar yaklaşımı benimsiyor ve eskiden sahip olduğumuz aynı HEAPTYPE-> HEAPTYPE kontrolünü ve bir de "beyaz liste" yi eski haline getiriyoruz. Şimdilik, beyaz liste sadece ModuleType alt türlerinden oluşuyor, çünkü bunlar yamayı ilk etapta motive eden vakalar - bkz. Https://bugs.python.org/issue22986 - ve modül nesneleri değiştirilebilir olduğundan emin olabiliriz kesinlikle stajyer olmamaları. Şimdi HEAPTYPE-> HEAPTYPE veya
ModuleType alt türü -> ModuleType alt türü.
Bildiğimiz kadarıyla, aşağıdaki 'if' ifadesinin ötesindeki tüm kodlar HEAPTYPE olmayan sınıfları doğru bir şekilde işleyecek ve HEAPTYPE denetimi yalnızca yorumlayıcının pişirdiği HEAPTYPE sınıflarının alt kümesini korumak için gereklidir. tüm örnekler gerçekten değişmezdir.
Açıklama:
CPython nesneleri iki şekilde depolar:
Nesneler öbek üzerinde tahsis edilen yapılardır. Düzgün çöp toplandıklarından emin olmak için nesnelerin kullanımına ilişkin özel kurallar geçerlidir. Nesneler hiçbir zaman statik olarak veya yığın üzerinde ayrılmaz; bunlara yalnızca özel makrolar ve işlevler aracılığıyla erişilmelidir. (Yazım nesneleri birinci kuralın istisnasıdır; Python 2.2 için yazım / sınıf birleştirme üzerinde yapılan çalışmalar yığın tahsisli yazım nesnelerine sahip olmayı mümkün kılsa da, standart türler statik olarak başlatılan yazım nesneleriyle temsil edilir).
Include / object.h içindeki yorumdan alınan bilgiler .
Olarak yeni bir değer ayarlamaya çalıştığınızda some_obj.__class__
, object_set_class
işlev çağrılır. PyBaseObject_Type kaynağından devralınır, alana bakın /* tp_getset */
. Bu işlev şunları denetler : yeni tür eski türün yerini alabilir some_obj
mi?
Örneğinizi alın:
class A:
pass
class B:
pass
o = object()
a = A()
b = B()
İlk durum:
a.__class__ = B
Tipi a
nesnesi olan A
dinamik tahsis edilir, çünkü yığın türü. Yanı sıra B
. a
Bireyin tip bir sorun olmadan değiştirilir.
İkinci durum:
o.__class__ = B
Türü o
yerleşik türdür object
( PyBaseObject_Type
). Öbek türü değildir, bu yüzden TypeError
yükseltilir:
TypeError: __class__ assignment only supported for heap types or ModuleType subclasses.