2.21. เมธอดและ attribute¶
เมธอด คือฟังก์ชันที่กำหนดภายในคลาส พารามิเตอร์แรกคือ instance ที่เมธอดถูกเรียกบนนั้น ธรรมเนียมคือตั้งชื่อว่า self
2.21.1. Instance methods¶
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def magnitude(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
p = Point(3, 4)
print(p.magnitude())
ผลลัพธ์:
5.0
การเรียก p.magnitude() ส่ง p เป็น self โดยอัตโนมัติ เนื้อหาของเมธอดอ่านและอัปเดต attribute ผ่าน self เช่นเดียวกับที่ฟังก์ชันอ่านและอัปเดตชื่อผ่านพารามิเตอร์
2.21.2. Instance vs class attributes¶
Attribute ที่กำหนดให้ self -- โดยทั่วไปอยู่ใน __init__ -- เป็นของ instance นั้นเพียงตัวเดียว:
a = Point(1, 2)
b = Point(10, 20)
a.x = 99
print(a.x, b.x) # 99 10
a.x และ b.x เป็นพื้นที่จัดเก็บที่แตกต่างกัน การเปลี่ยนแปลงอันหนึ่งไม่มีผลต่ออีกอัน
ชื่อที่กำหนดในเนื้อหาคลาส นอก เมธอดใดๆ ถูกแบ่งปันโดยทุก instance ของคลาส:
class Counter:
kind = "tally" # class attribute -- shared
def __init__(self):
self.value = 0 # instance attribute -- per instance
a = Counter()
b = Counter()
print(a.kind, b.kind) # tally tally
Class attribute อยู่บนคลาสและถูกแบ่งปัน Instance attribute อยู่บน instance แต่ละตัว¶
class attribute เข้าถึงได้ในแบบเดียวกับ instance attribute (a.kind) Python มองหาที่ instance ก่อน แล้วจึงมองที่คลาส การกำหนด a.kind จะสร้าง instance attribute ใหม่ที่บดบัง class attribute โดยปล่อย b.kind ไม่เปลี่ยนแปลง
ใช้ class attribute สำหรับค่าคงที่และค่าเริ่มต้นที่ทุก instance ควรมองเห็นในแบบเดียวกัน ใช้ instance attribute สำหรับสถานะที่แต่ละออบเจ็กต์ควรมีสำเนาของตัวเอง
2.21.3. __str__ and __repr__¶
เมธอดพิเศษสองตัวควบคุมวิธีที่ instance แสดงผล __str__ คืนค่าสตริง "เป็นมิตร" ที่ใช้โดย print() ส่วน __repr__ คืนค่าสตริง "สำหรับนักพัฒนา" ที่ใช้ใน REPL และในการแสดงผลของคอนเทนเนอร์:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "(" + str(self.x) + ", " + str(self.y) + ")"
def __repr__(self):
return "Point(" + str(self.x) + ", " + str(self.y) + ")"
p = Point(3, 4)
print(p) # uses __str__
print([p, p]) # uses __repr__ inside the list
ผลลัพธ์:
(3, 4)
[Point(3, 4), Point(3, 4)]
ถ้ากำหนดเฉพาะ __repr__ เท่านั้น print() จะใช้มันแทน -- ดังนั้น __repr__ ที่เขียนดีเพียงตัวเดียวมักจะเพียงพอ กำหนด __str__ เพิ่มเมื่อรูปแบบที่เป็นมิตรควรดูต่างจากรูปแบบสำหรับนักพัฒนาเท่านั้น พยายามทำให้ __repr__ ดูเหมือนการเรียกที่จะสร้างออบเจ็กต์ขึ้นใหม่ การ debug จะง่ายขึ้นอย่างเห็นได้ชัดเมื่อค่าที่พิมพ์ออกมาไม่กำกวม