ตัวบอกคุณสมบัติ: __get__, __set__, __delete__
นำโพรโทคอลตัวบอกคุณสมบัติมาใช้เพื่อควบคุมการเข้าถึงแอตทริบิวต์
ตัวบอกคุณสมบัติ: __get__, __set__, __delete__ เป็นบทเรียน Python Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Python Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน
ตัวบอกลักษณะคืออะไร
ตัวบอกลักษณะคืออ็อบเจ็กต์ที่กำหนด __get__ __set__ หรือ __delete__ และกำหนดให้เป็นแอตทริบิวต์ของ คลาส Python จะเรียกเมธอดเหล่านี้เมื่อมีการเข้าถึงแอตทริบิวต์
class Descriptor:
def __get__(self, obj, objtype=None):
print(f"__get__ called, obj={obj}")
return 42
class MyClass:
attr = Descriptor()
print(MyClass().attr) # __get__ called ... 42ตัวบอกลักษณะข้อมูลเทียบกับตัวบอกลักษณะที่ไม่ใช่ข้อมูล
ตัวบอกลักษณะข้อมูล กำหนด __set__ หรือ __delete__ และมีลำดับความสำคัญเหนือ __dict__ ของอินสแตนซ์ ส่วน ตัวบอกลักษณะที่ไม่ใช่ข้อมูล ซึ่งมีเพียง __get__ จะมีลำดับความสำคัญรองจาก __dict__
class DataDesc:
def __get__(self, obj, t): return "data"
def __set__(self, obj, val): pass
class NonDataDesc:
def __get__(self, obj, t): return "nondata"
class C:
d = DataDesc()
n = NonDataDesc()
c = C()
c.__dict__["n"] = "instance" # shadows the non-data desc
c.__dict__["d"] = "instance" # does NOT shadow data desc
print(c.n) # instance
print(c.d) # dataลายเซ็นของ __get__
__get__(self, obj, objtype): obj คืออินสแตนซ์ หรือเป็น None เมื่อเข้าถึงจากคลาส ส่วน objtype คือคลาส
class Verbose:
def __get__(self, obj, objtype=None):
if obj is None:
return self # accessed on class
return f"value for {obj!r}"
class Widget:
label = Verbose()
print(Widget.label) # <Verbose object>
print(Widget().label) # value for <Widget object>__set__ และการตรวจสอบความถูกต้อง
ใช้งาน __set__(self, obj, value) เพื่อตรวจสอบหรือแปลงค่าก่อนจัดเก็บ
class PositiveInt:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, t):
return obj.__dict__.get(self.name)
def __set__(self, obj, val):
if not isinstance(val, int) or val <= 0:
raise ValueError(f"{self.name} must be a positive int")
obj.__dict__[self.name] = val
class Rect:
width = PositiveInt()
height = PositiveInt()
r = Rect()
r.width = 10
# r.width = -1 # ValueError__set_name__
Python 3.6 ขึ้นไปจะเรียก __set_name__(owner, name) บนตัวบอกลักษณะเมื่อกำหนดตัวบอกลักษณะให้กับคลาส ทำให้ตัวบอกลักษณะเข้าถึงชื่อแอตทริบิวต์ของตนเองได้
class Typed:
def __set_name__(self, owner, name):
self.public = name
self.private = "_" + name
def __get__(self, obj, t):
return None if obj is None else getattr(obj, self.private, None)
def __set__(self, obj, val):
setattr(obj, self.private, val)
class User:
name = Typed()
u = User()
u.name = "Alice"
print(u.name) # Alice__delete__ สำหรับการลบแอตทริบิวต์
กำหนด __delete__(self, obj) เพื่อดักการทำงานของ del obj.attr
class Protected:
def __set_name__(self, owner, name): self.name = name
def __get__(self, obj, t):
return obj.__dict__.get(self.name)
def __set__(self, obj, v): obj.__dict__[self.name] = v
def __delete__(self, obj):
raise AttributeError(f"Cannot delete {self.name}")
class Config:
host = Protected()
c = Config(); c.host = "localhost"
# del c.host # AttributeErrorฟังก์ชันเป็นตัวบอกลักษณะที่ไม่ใช่ข้อมูล
ฟังก์ชันใช้งาน __get__ เพื่อคืนค่าเมธอดที่ผูกกับอินสแตนซ์เมื่อเข้าถึงจากอินสแตนซ์ นี่คือวิธีที่ Python ผูกเมธอดเข้ากับอินสแตนซ์
def greet(self):
return f"Hello from {self}"
class C: pass
C.greet = greet
c = C()
print(c.greet()) # Hello from <C object>classmethod และ staticmethod เป็นตัวบอกลักษณะ
classmethod และ staticmethod เป็นคลาสตัวบอกลักษณะในตัวที่ห่อฟังก์ชันและเปลี่ยนค่าที่ __get__ คืนกลับ
class MyClass:
@classmethod
def from_string(cls, s):
return cls()
# classmethod.__get__ returns a bound method with cls
# staticmethod.__get__ returns the plain functionตัวบอกลักษณะแอตทริบิวต์แบบประเมินเมื่อจำเป็น
สร้างตัวบอกลักษณะที่คำนวณค่าเพียงครั้งเดียวและแคชค่านั้นแยกไว้สำหรับแต่ละอินสแตนซ์
class LazyAttr:
def __init__(self, func): self.func = func
def __set_name__(self, owner, name): self.name = name
def __get__(self, obj, t):
if obj is None: return self
val = self.func(obj)
obj.__dict__[self.name] = val # shadows descriptor
return val
class Report:
@LazyAttr
def summary(self):
print("computing...")
return "done"
r = Report()
print(r.summary) # computing... done
print(r.summary) # done (cached)property เป็นตัวบอกลักษณะ
property เป็นตัวบอกลักษณะข้อมูลที่เขียนด้วยภาษา C โดยตัวมันเอง การทำความเข้าใจตัวบอกลักษณะจะช่วยให้คุณเข้าใจการทำงานของ @property @classmethod และ @staticmethod
class Circle:
def __init__(self, r): self._r = r
@property
def radius(self): return self._r
@radius.setter
def radius(self, v):
if v < 0: raise ValueError
self._r = v
# property is: property.__get__ = fget, property.__set__ = fsetลำดับการค้นหาดีสคริปเตอร์
ลำดับการค้นหาแอตทริบิวต์ใน Python คือ 1) ดีสคริปเตอร์ข้อมูลจากชนิดข้อมูล (MRO) 2) พจนานุกรม __dict__ ของอินสแตนซ์ 3) ดีสคริปเตอร์ที่ไม่ใช่ข้อมูลและตัวแปรของคลาส
# Pseudocode for obj.attr:
# 1. Check type(obj).__mro__ for a data descriptor
# 2. Check obj.__dict__
# 3. Check type(obj).__mro__ for non-data descriptor or class var
# 4. Raise AttributeErrorตรวจสอบความเข้าใจอย่างรวดเร็ว
ดีสคริปเตอร์ชนิดใดมีลำดับความสำคัญเหนือกว่า __dict__ ของอินสแตนซ์
สรุป
ดีสคริปเตอร์ดักรับการเข้าถึงแอตทริบิวต์ผ่าน __get__, __set__ และ __delete__ ดีสคริปเตอร์ข้อมูลจะบดบัง __dict__ ของอินสแตนซ์ ส่วนดีสคริปเตอร์ที่ไม่ใช่ข้อมูลจะไม่ทำเช่นนั้น ใช้ __set_name__ เพื่อรับรู้ชื่อแอตทริบิวต์ property, classmethod และ staticmethod ล้วนเป็นดีสคริปเตอร์
คำถามที่พบบ่อย
บทเรียน “ตัวบอกคุณสมบัติ: __get__, __set__, __delete__” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ตัวบอกคุณสมบัติ: __get__, __set__, __delete__” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Python Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Python Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ตัวบอกคุณสมบัติ: __get__, __set__, __delete__”
นำโพรโทคอลตัวบอกคุณสมบัติมาใช้เพื่อควบคุมการเข้าถึงแอตทริบิวต์ คุณปฏิบัติ Python Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Python Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Python Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “ตัวบอกคุณสมบัติ: __get__, __set__, __delete__” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Python Academy นี้ได้ไหม
ได้ บทเรียน Python Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การสร้างคลาสของ Python
- การเขียนเมตาคลาสแบบกำหนดเอง
- ตัวบอกคุณสมบัติ: __get__, __set__, __delete__
- __slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ