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_getattroben bakarak aşağı izlenen "tp_slots" sonra tp_getattro doldurulur . Ve B.vbaş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 = 3tetikleyiciden 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 = 3vv.__set__
Yasal Uyarı 1: Python'u printfs ile kaynaktan yeniden oluşturmadım, bu yüzden type_setattrosı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 = 3ile 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 = 3Sınıf tanımlayıcısının neden üzerine yazılabileceğini merak ediyorum . CPython uygulamasına dayanarak, B.v = 3tetiklemeyi de bekliyordum __set__.