ข้ามไปยังเนื้อหา

Dunder Methods

Dunder methods (ย่อมาจาก double-underscore) เป็น special methods เช่น __repr__, __eq__ และ __add__ ที่ Python เรียกอัตโนมัติเพื่อตอบสนองต่อ built-in syntax และฟังก์ชัน สิ่งเหล่านี้เป็นกลไกเบื้องหลัง Python Data Model — สัญญาที่ทำให้ object ของคุณทำงานเหมือน built-in types

ทั้งคู่สร้าง string representation แต่เพื่อกลุ่มเป้าหมายต่างกัน:

Methodเมื่อไหร่ถูกเรียกวัตถุประสงค์
__repr__repr(obj), interactive shellRepresentation ที่ชัดเจนสำหรับนักพัฒนา
__str__str(obj), print(obj)การแสดงผลที่อ่านง่ายสำหรับมนุษย์

ถ้ากำหนดเฉพาะ __repr__ Python จะใช้ __repr__ สำหรับทั้งสองกรณี Convention สำหรับ __repr__ คือ return string ที่ถ้าส่งผ่าน eval() จะสร้าง object ขึ้นมาใหม่ได้

class Point:
def __init__(self, x: float, y: float) -> None:
self.x = x
self.y = y
def __repr__(self) -> str:
return f"Point({self.x}, {self.y})"
def __str__(self) -> str:
return f"({self.x}, {self.y})"

Python เรียก __eq__ เมื่อเขียน a == b หากไม่มี __eq__ == จะ fallback ไปใช้ identity comparison (is) — สอง instance แยกกันที่มีข้อมูลเหมือนกันจะไม่เท่ากันเลย

def __eq__(self, other: object) -> bool:
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y

Return NotImplemented (ไม่ใช่ False) เมื่อ type ไม่เข้ากัน — เพื่อให้ Python ลอง reflected operation บน operand อีกตัว

Implement __len__ เพื่อรองรับ len(obj) Implement __getitem__ เพื่อรองรับ obj[index] subscript access ทั้งคู่รวมกันทำให้ object iterable ผ่าน for loop ด้วย (Python เรียก __getitem__ ด้วย 0, 1, 2, … จนถึง IndexError)

def __len__(self) -> int:
return 2
def __getitem__(self, index: int) -> float:
return (self.x, self.y)[index]

Arithmetic operators map ไปยัง dunder methods:

OperatorMethod
a + ba.__add__(b)
a - ba.__sub__(b)
a * ba.__mul__(b)
a == ba.__eq__(b)
a < ba.__lt__(b)
def __add__(self, other: "Vector") -> "Vector":
return Vector(self.x + other.x, self.y + other.y)
class Vector:
def __init__(self, x: float, y: float) -> None:
self.x = x
self.y = y
def __repr__(self) -> str:
return f"Vector({self.x}, {self.y})"
def __str__(self) -> str:
return f"({self.x}, {self.y})"
def __eq__(self, other: object) -> bool:
if not isinstance(other, Vector):
return NotImplemented
return self.x == other.x and self.y == other.y
def __add__(self, other: "Vector") -> "Vector":
return Vector(self.x + other.x, self.y + other.y)
def __len__(self) -> int:
return 2
def __getitem__(self, index: int) -> float:
return (self.x, self.y)[index]
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(repr(v1))
print(str(v1))
print(v1 == Vector(1, 2))
print(v1 + v2)
print(len(v1))
print(v1[0], v1[1])
ความแตกต่างระหว่าง `__repr__` และ `__str__` คืออะไร?
`__eq__` ควร return `NotImplemented` แทน `False` เมื่อใด?
`v1 + v2` เรียก dunder method ใดบน `v1`?
ถ้า class implement `__len__` และ `__getitem__` Python จะอนุญาตให้ทำอะไรได้อีกอัตโนมัติ?