0Pricing
Python Academy · บทเรียน

ตัวบอกคุณสมบัติ: __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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การสร้างคลาสของ Python
  2. การเขียนเมตาคลาสแบบกำหนดเอง
  3. ตัวบอกคุณสมบัติ: __get__, __set__, __delete__
  4. __slots__ และการเพิ่มประสิทธิภาพหน่วยความจำ
← กลับไปที่ Python Academy