เล่นง่าย:
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
คำถามนี้มีการทำสำเนาที่มีประสิทธิภาพแต่การทำซ้ำไม่ได้รับคำตอบและฉันขุดลงในแหล่งที่มาของ CPython เป็นแบบฝึกหัดการเรียนรู้อีกเล็กน้อย คำเตือน: ฉันเข้าไปในวัชพืช ฉันจริงๆหวังว่าฉันจะได้รับความช่วยเหลือจากกัปตันที่รู้น้ำเหล่านั้น ฉันพยายามอย่างชัดเจนที่สุดเท่าที่จะเป็นไปได้ในการติดตามการโทรที่ฉันกำลังดูเพื่อผลประโยชน์ในอนาคตของฉันเองและประโยชน์ของผู้อ่านในอนาคต
ฉันเห็นหมึกจำนวนมากหกใส่ลงบนลักษณะการ__getattribute__ใช้งานของคำอธิบายเช่นการค้นหามาก่อน งูหลาม snippet ใน"อัญเชิญอธิบาย"เพียงด้านล่างFor classes, the machinery is in type.__getattribute__()...ประมาณตกลงในใจของฉันกับสิ่งที่ผมเชื่อว่าเป็นที่สอดคล้องแหล่ง CPythonในtype_getattroซึ่งผมติดตามลงโดยดูที่"tp_slots"แล้วที่ tp_getattro เป็นประชากร และความจริงที่ว่าการB.vพิมพ์ครั้งแรกนั้น__get__, obj=None, objtype=<class '__main__.B'>สมเหตุสมผลสำหรับฉัน
สิ่งที่ฉันไม่เข้าใจคือทำไมมอบหมายB.v = 3สุ่มสี่สุ่มห้าเขียนทับบ่งมากกว่าวิกฤติv.__set__? ผมพยายามที่จะติดตามการโทร CPython เริ่มต้นอีกครั้งจาก"tp_slots"แล้วมองหาที่ที่มีประชากร tp_setattroแล้วมองไปที่type_setattro type_setattro ดูเหมือนจะเป็นเสื้อคลุมบาง ๆ รอบ_PyObject_GenericSetAttrWithDict และมีปมของความสับสนของฉัน: _PyObject_GenericSetAttrWithDictดูเหมือนจะมีตรรกะที่ให้ความสำคัญกับคำอธิบายถึงของ__set__วิธี !! กับในใจฉันไม่สามารถคิดออกว่าทำไมB.v = 3สุ่มสี่สุ่มห้าเขียนทับมากกว่าวิกฤติvv.__set__
ข้อสงวนสิทธิ์ 1: ฉันไม่ได้สร้าง Python ใหม่จากแหล่งที่มาด้วย printfs ดังนั้นฉันไม่แน่ใจว่าtype_setattroสิ่งที่ถูกเรียกระหว่างB.v = 3นั้น
ข้อจำกัดความรับผิดชอบ 2: VocalDescriptorไม่ได้มีไว้เพื่อเป็นตัวอย่างคำจำกัดความตัวอธิบาย "ปกติ" หรือ "แนะนำ" มันไม่มีทางเลือกที่จะบอกฉันเมื่อมีการเรียกวิธีการ
__get__ทำงานได้มากกว่าที่จะ__set__ทำไม่ได้
__get__เมธอด ได้เขียนทับได้อย่างมีประสิทธิภาพแอตทริบิวต์ที่มีB.v = 3 int
__get__มีการเรียกและการใช้งานเริ่มต้นของobject.__getattribute__และtype.__getattribute__เรียกใช้__get__เมื่อใช้อินสแตนซ์หรือคลาส การกำหนดผ่าน__set__เป็นเพียงตัวอย่างเท่านั้น
__get__เมธอดdescriptors ควรถูกเรียกใช้เมื่อเรียกใช้จากคลาส นี่คือวิธีที่ @classmethods และ @staticmethods จะดำเนินการตามวิธีการแนะนำ @ Jab ฉันสงสัยว่าทำไมB.v = 3สามารถเขียนทับตัวบอกคลาสได้ จากการใช้งาน CPython ฉันคาดว่าB.v = 3จะเปิดใช้งาน__set__เช่นกัน