Basit repro:
class VocalDescriptor(object):
def __get__(self, obj, objtype):
print('__get__, obj={}, objtype={}'.format(obj, objtype))
def __set__(self, obj, val):
print('__set__')
class B(object):
v = VocalDescriptor()
B.v # prints "__get__, obj=None, objtype=<class '__main__.B'>"
B.v = 3 # does not print "__set__", evidently does not trigger descriptor
B.v # does not print anything, we overwrote the descriptor
Bu sorunun etkili bir kopyası var , ancak kopyası cevaplanmadı ve CPython kaynağına bir öğrenme alıştırması olarak biraz daha girdim. Uyarı: Yabancı otların içine girdim. Gerçekten bu suları bilen bir kaptandan yardım alabileceğimi umuyorum . Kendi gelecekteki ve gelecekteki okuyucuların yararına baktığım çağrıların izlenmesinde mümkün olduğunca açık olmaya çalıştım.
__getattribute__
Tanımlayıcılara uygulanan davranışlar üzerine dökülen çok fazla mürekkep gördüm , örneğin arama önceliği. Python pasajı "çağırma Açıklayıcılar" hemen altında For classes, the machinery is in type.__getattribute__()...
kabaca ben tekabül inandığımız ile zihnimde kabul eder CPython kaynak içinde type_getattro
ben bakarak aşağı izlenen "tp_slots" sonra tp_getattro doldurulur . Ve B.v
başlangıçta basan gerçeğin __get__, obj=None, objtype=<class '__main__.B'>
benim için anlamı var.
Anlamadığım şey, ödev neden B.v = 3
tetikleyiciden ziyade tanımlayıcının üzerine körü körüne yazılıyor v.__set__
? Ben bir kez daha başlayarak CPython Numarayı tespit etmeye çalıştılar "tp_slots" ardından bakarak, tp_setattro doldurulur nerede o bakarak, type_setattro . type_setattro
görünmektedir etrafında ince bir sargı _PyObject_GenericSetAttrWithDict . Ve karışıklığımın temel noktası var: bir tanımlayıcının yöntemine öncelik veren mantığa_PyObject_GenericSetAttrWithDict
sahip gibi görünüyor !! Bunu akılda tutarak, neden tetiklemek yerine körü körüne yazıldığını anlayamıyorum .__set__
B.v = 3
v
v.__set__
Yasal Uyarı 1: Python'u printfs ile kaynaktan yeniden oluşturmadım, bu yüzden type_setattro
sırasında ne denildiğinden tam olarak emin değilim B.v = 3
.
Feragat 2: VocalDescriptor
"tipik" veya "önerilen" tanımlayıcı tanımını örneklemek amacında değildir. Metodların ne zaman çağrıldığını bana söylemek, kapsamlı bir hayır.
__get__
işe yaramadı , neden işe __set__
yaramadı.
__get__
yöntemi çağırmayı bekliyor . B.v = 3
ile etkin bir şekilde özelliğin üzerine yazmıştır int
.
__get__
çağrılmayacağını ve bir örneği veya sınıfı kullanırken varsayılan uygulamalarını belirler object.__getattribute__
ve type.__getattribute__
çağırır __get__
. Üzerinden atama__set__
sadece örnek içindir.
__get__
yöntemlerinin sınıfın kendisinden çağrıldığında tetiklenmesi gerektiğine inanıyorum . Nasıl yapılır kılavuzuna göre @classmethods ve @staticmethods bu şekilde uygulanır . @Jab B.v = 3
Sınıf tanımlayıcısının neden üzerine yazılabileceğini merak ediyorum . CPython uygulamasına dayanarak, B.v = 3
tetiklemeyi de bekliyordum __set__
.