ภาษาไพธอนเป็นภาษาที่เน้นรูปแบบการเขียนในเชิงวัตถุ ข้อมูลชนิดต่างๆในภาษาไพธอนอยู่ในรูปของสิ่งที่เรียกว่า
ออบเจ็กต์ (object) และออบเจ็กต์ก็มีรูปแบบชนิดต่างๆมากมายไม่จำกัด เพราะนอกเหนือจากออบเจ็กต์มาตรฐานแล้วเราสามารถสร้างออบเจ็กต์ชนิดใหม่ขึ้นมาได้เองตามที่ต้องการ
ในการเขียนโปรแกรมเชิงวัตถุ ออบเจ็กต์จะถูกแบ่งเป็นหมวดหมู่ที่เรียกว่า
คลาส (class) การสร้างคลาส ในเรื่องของการสร้างคลาสนี้เป็นเรื่องที่เข้าใจยากพอสมควรทีเดียว เพื่อให้เห็นภาพชัดจะขออธิบายโดยเริ่มจากการยกตัวอย่าง โดยสมมุติว่าถ้าเราต้องการสร้างเกมขึ้นมา
คิดว่าทุกคนคงจะต้องเคยเล่นเกมแนวแฟนตาซีกัน โดยทั่วไปการดำเนินเรื่องจะเป็นในลักษณะที่ผู้เล่นคนหนึ่งก็เล่นเป็นตัวละครตัวหนึ่ง เป็นผู้กล้าแล้วก็ไปสู้กับปีศาจ
ภาพประกอบจากอนิเมะเรื่องผู้กล้าโล่ผงาด (ที่มา) ตัวละครที่ผู้เล่นใช้นั้นก็มักจะประกอบไปด้วยค่าสถานะต่างๆ เช่น พลังโจมตี, พลังป้องกัน, HP, ฯลฯ
หากต้องการเขียนโปรแกรมเชิงวัตถุเพื่อสร้างเกมในลักษณะนี้ขึ้นมา เราอาจกำหนดให้ตัวละครแต่ละตัวเป็นออบเจ็กต์ แล้วค่าสถานะต่างๆก็คือแอตทริบิวต์ ซึ่งก็คือค่าองค์ประกอบบางอย่างที่ติดตัวออบเจ็กต์
การสร้างคลาสทำได้โดยใช้คำสั่ง
class
แล้วตามด้วยชื่อคลาสที่ต้องการตั้ง ตามด้วยโคลอน
:
จากนั้นก็ตามด้วยบรรทัดที่ร่นเข้าซึ่งในนั้นใส่เนื้อหาโครงสร้างต่างๆของคลาส
class ชื่อคลาส:
เนื้อหาของคลาส
โดยทั่วไปแล้วชื่อคลาสจะขึ้นต้นด้วยตัวพิมพ์ใหญ่ นี่เป็นธรรมเนียมปฏิบัติแม้ว่าจะไม่ได้เป็นข้อบังคับอะไร
อย่างไรก็ตาม ไพธอน 3 นั้นสามารถตั้งชื่อตัวแปรโดยใช้อักษรอะไรก็ได้ ซึ่งรวมถึงชื่อคลาสและชื่อออบเจ็กต์ด้วย ตอนนี้เราจะมาใช้ประโยชน์จากตรงนี้ดู เพื่อความเข้าใจง่ายจะตั้งชื่อตัวแปรต่างๆทั้งคลาสและออบเจ็กต์เป็นภาษาไทยทั้งหมด
ในการสร้างคลาส คลาสที่สร้างขึ้นอาจมีความซับซ้อน ใส่แอตทริบิวต์และเมธอดไปมากมายอย่างละเอียด แต่ในขณะเดียวกันก็สามารถสร้างคลาสที่โล่งๆไม่มีอะไรเลยก็ได้
คือสร้างขึ้นมาได้โดยไม่ต้องกำหนดอะไรเลย เป็นคลาสเปล่าๆ ในตอนเริ่มต้นนี้ขอเริ่มต้นยกตัวอย่างจากการสร้างคลาสว่างๆ
class ผู้กล้า:
0
นี่เป็นรูปแบบการสร้างคลาสที่สั้นที่สุดที่จะสามารถสร้างได้ ถึงอย่างนั้นแค่นี้ก็เป็นการสร้างคลาสที่ชื่อว่า
ผู้กล้า
ขึ้นมาแล้ว ซึ่งจะเห็นว่าคลาสนี้ว่างเปล่า แบบนี้ออบเจ็กต์ที่สร้างขึ้นจากคลาสนี้ก็จะไม่มีคุณสมบัติอะไรติดตัวเป็นพิเศษ
เลข
0
ที่อยู่ในบรรทัดที่ร่นเข้ามานั้นในที่นี้ไม่ได้ทำหน้าที่อะไรแค่ใส่เอาไว้เฉยๆเพื่อไม่ให้โครงสร้างคลาสว่างเปล่า
***บางคนก็นิยมใช้
pass
ซึ่งเป็นคำสั่งที่ไม่มีการทำงานแต่ใส่เอาไว้เฉยๆเพื่อกันไม่ให้โครงสร้าง ว่างเปล่า แต่ก็ไม่ได้มีความจำเป็นต้องใช้ดังนั้นในที่นี้จะใช้
0
แทนเมื่อต้องการโครงสร้างที่ว่างเปล่า
เพราะโดยปกติแล้วเวลาสร้าง คลาสควรจะมีอะไรอยู่ภายในโครงสร้างคลาส (คือบริเวณบรรทัดที่ร่นอยู่หลังโคลอน
:
) แต่ถ้าไม่ต้องการใส่อะไรเลยก็อาจใส่อะไรสักอย่างที่ไม่แสดงผล
การสร้างออบเจ็กต์ของคลาสนี้ขึ้นมาทำได้โดยใส่ชื่อตัวแปรที่จะใช้เป็นออบเจ็กต์ ตามด้วยเครื่องหมายเท่ากับ
=
แล้วก็ชื่อคลาสตามด้วยวงเล็บ เช่น
ผู้เล่น1 = ผู้กล้า()
เท่านี้ก็จะได้ออบเจ็กต์ที่ชื่อว่า
ผู้เล่น1
ซึ่งเป็นออบเจ็กต์ในคลาส
ผู้กล้า
ออบเจ็กต์ที่ได้จากการเรียกใช้คลาสในลักษณะนี้จะถูกเรียกว่าคลาสอินสแตนซ์ (class instance, หรือเรียก "อินสแตนซ์" เฉยๆ) ของคลาสนั้น ในกรณีนี้ก็คือ
ผู้เล่น1
เป็นคลาสอินสแตนซ์ของคลาส
ผู้กล้า
การใช้คำอาจดูแปลกๆ นี่เป็นการพูดแบบใช้ศัพท์เทคนิค ถ้าจะยกตัวอย่างให้เป็นรูปธรรมก็คือ "
ผู้เล่น1
เป็น
ผู้กล้า
คนหนึ่ง" แบบนั้นอาจดูเข้าใจง่ายกว่า
ก็ผู้กล้าอาจมีกี่คนก็ได้ คือจะสร้างผู้กล้าขึ้นมาใหม่กี่คนก็ได้ สมมุติว่ามีผู้เล่นใหม่เพิ่มเข้ามาอีกคนก็สร้างตัวละครขึ้นมาใหม่
ผู้เล่น2 = ผู้กล้า()
เท่านี้ก็ได้ผู้กล้ามาอีกคนแล้ว ทั้ง
ผู้เล่น1
และ
ผู้เล่น2
ต่างก็เป็น
ผู้กล้า
ทั้งคู่ ลองใช้
type
เพื่อหาชนิดดูได้ ก็จะได้ชนิดเป็นคลาสนั้น
print(type(ผู้เล่น1)) # ได้ <class '__main__.ผู้กล้า'>
__main__.
ที่เห็นอยู่ด้านหน้าชื่อคลาสที่เราตั้งนี้คือส่วนที่แสดงว่าคลาสนี้ถูกสร้าง ขึ้นภายในโปรแกรมหลัก ไม่ได้เป็นคลาสที่ถูกสร้างขึ้นจากในมอดูลไหนที่เราเรียกใช้เข้ามา
ออบเจ็กต์ที่สร้างขึ้นมาใหม่จะมีคุณสมบัติเริ่มต้นตามที่มันควรจะมีสำหรับคลาส ของมัน แต่ตอนนี้เราแค่สร้างคลาสเปล่าๆขึ้นมาจึงยังไม่มีอะไร
แต่ว่าแม้แต่คลาสที่ว่างเปล่าก็สามารถที่จะป้อนค่าแอตทริบิวต์ให้เมื่อไหร่ก็ได้
class ผู้กล้า:
0
ผู้เล่น1 = ผู้กล้า()
ผู้เล่น2 = ผู้กล้า()
ผู้เล่น1.ชื่อ = 'เก่งกล้า'
ผู้เล่น1.พลังโจมตี = 5
ผู้เล่น1.พลังป้องกัน = 4
ผู้เล่น2.ชื่อ = 'ชำนาญ'
ผู้เล่น2.พลังโจมตี = 6
ผู้เล่น2.พลังป้องกัน = 3
การป้อนค่าในลักษณะแบบนี้ก็ดูคล้ายกับการป้อนค่าตัวแปรจำนวนเต็มธรรมดา แต่อย่างไรก็ตามนี่ไม่ใช่เป็นการสร้างตัวแปรที่ชื่อ
ผู้เล่น1.พลังโจมตี
เพราะอย่าลืมว่าชื่อตัวแปรจะต้องไม่มีจุด
.
ดังนั้นตรงนี้จึงมีความหมายว่าสร้างแอตทริบิวต์ที่ชื่อว่า
พลังโจมตี
ให้กับออบเจ็กต์
ผู้เล่น1
พร้อมกับป้อนค่าให้
จุดในที่นี้เป็นเหมือนสัญลักษณ์เชื่อมต่อแสดงความสัมพันธ์ระหว่างหน่วยเล็กกับหน่วยใหญ่ โดยทางซ้ายเป็นหน่วยใหญ่ ในที่นี้ทางซ้ายจุดคือออบเจ็กต์ ส่วนทางขวาจุดคือแอตทริบิวต์ของออบเจ็กต์นั้น
สิ่งที่อยู่ทางขวาของจุดอาจไม่ใช่แอตทริบิวต์แต่อาจเป็นเมธอด เมธอดก็เป็นอีกสิ่งหนึ่งที่จะเห็นเขียนในรูปจุดต่อท้ายออบเจ็กต์ แต่ว่าสิ่งที่ต่างคือเมธอดจะต้องมีวงเล็บตามหลังเสมอ ส่วนแอตทริบิวต์จะไม่มี
เรื่องของการสร้างเมธอดจะอธิบายต่อไป ตอนนี้ขอพูดถึงแอตทริบิวต์ก่อน
แอตทริบิวต์ของออบเจ็กต์ที่สร้างขึ้นมานี้จะมีคุณสมบัติเหมือนกับตัวแปรทั่วไป สามารถใช้
print
แล้วก็นำมาคำนวณได้ และสามารถแก้ค่าได้ตามที่ต้องการ
print(ผู้เล่น1.พลังโจมตี) # ได้ 5
ผู้เล่น1.พลังโจมตี = ผู้เล่น1.พลังโจมตี - 1
print(ผู้เล่น1.พลังโจมตี) # ได้ 4
และถ้าหาชนิดของแอตทริบิวต์ดูก็จะได้เป็นชนิดเหมือนกับข้อมูลทั่วๆไป เช่นในที่นี้เป็นจำนวนเต็ม
print(type(ผู้เล่น1.พลังโจมตี)) # ได้ <class 'int'>
พอพูดแบบนี้ก็อาจมีคนสงสัยว่า ถ้าอย่างนั้นแล้วจะอุตส่าห์สร้างเป็นออบเจ็กต์และแอตทริบิวต์ทำไม ต่างอะไรกับการสร้างตัวแปรใหม่ เช่น
พลังโจมตีของผู้เล่น1 = 5
อะไรทำนองนี้ก็จะได้ตัวแปรที่ทำหน้าแสดงค่า
พลังโจมตีของผู้เล่น1
ได้ไม่ต่างกันเลย
หากมองในแง่นั้นก็อาจจะจริงอยู่ แต่ความจริงแล้วการทำแบบนี้มีประโยชน์มากมาย เช่นทำให้ได้โครงสร้างที่ดูเป็นระบบ อาจเทียบได้เหมือนกับต้นไม้ คือมีต้นหลักแล้วแตกสาขาออกไป สามารถเชื่อมโยงความสัมพันธ์ได้
หมายความว่าถ้าเราเห็นแอตทริบิวต์
ผู้เล่น1.พลังโจมตี = 5
ผู้เล่น1.พลังป้องกัน = 4
เราสามารถโยงความสัมพันธ์ได้ทันทีว่าทั้งสองค่านี้เป็นค่าที่เกี่ยวข้องหรือเป็นของ
ผู้เล่น1
ในขณะที่หากเก็บในตัวแปรธรรมดาแยกกันเช่น
พลังโจมตีของผู้เล่น1 = 5
พลังป้องกันของผู้เล่น1 = 4
แบบนี้แม้จะตั้งชื่อให้ดูสัมพันธ์กัน แต่ในเชิงโปรแกรมแล้วไม่มีอะไรที่เป็นตัวบอกถึงความเชื่อมโยง เพราะชื่อของตัวแปรมีแค่เพื่อความสะดวกไว้ให้คนเขียนโปรแกรมแยกแยะได้ง่าย เท่านั้น แต่ตัวคอมไพเลอร์ของโปรแกรมไม่ได้สนว่าชื่อตัวแปรจะเป็นยังไง เหมือนกันแค่ไหน ขอแค่ต่างกันก็จะถือว่าเป็นคนละตัวแปรกัน และไม่ได้เกี่ยวพันอะไรกับตัวแปรตัวอื่น
นั่นก็เป็นความสำคัญอย่าง หนึ่งของการใช้ออบเจ็กต์และแอตทริบิวต์ แต่อีกเหตุผลที่สำคัญก็คือแอตทริบิวต์สามารถใช้ร่วมกับเมธอดของออบเจ็กต์ได้
การสร้างเมธอด ในบทที่ผ่านๆมานั้นก็ได้พูดถึงเมธอดไปพอสมควรแล้ว ได้เห็นเมธอดของออบเจ็กต์มาตรฐานชนิดต่างๆ เช่นจำนวนเต็ม จำนวนจริง, ลิสต์, สายอักขระ
และจะเห็นว่าออบเจ็กต์แต่ละชนิดก็มีเมธอดต่างกันออกไป เช่นสายอักขระสามารถใช้เมธอด
split()
,
upper()
จำนวนจริงสามารถใช้
is_integer()
เป็นต้น
ออบเจ็กต์ที่เราสร้างขึ้นมาเองจากคลาสก็สามารถมีเมธอดได้เช่นกัน โดยเราจะต้องกำหนดขึ้นตอนที่สร้างคลาส
การสร้างเมธอดจะคล้ายกับการสร้างฟังก์ชัน นั่นคือใช้คำสั่ง
def
เพียงแต่ต่างกันแค่ว่า
def
จะต้องอยู่ภายในโครงสร้างของคลาส
เพราะจริงๆแล้วเมธอดก็คือฟังก์ชันที่นิยามขึ้นเพื่อจำเพาะใช้กับออบเจ็กต์ของคลาสนั่นเอง ถ้า
def
ใช้นอกคลาสมันก็จะเป็นฟังก์ชันธรรมดา แต่ถ้า
def
ภายในคลาสก็จะกลายเป็นฟังก์ชันของคลาส ซึ่งก็คือเมธอด
ในที่นี้จะขอยกตัวอย่างต่อจากตัวอย่างที่แล้ว โดยจะสร้างคลาสเหมือนเดิมแต่ใส่เมธอดลงไปให้มีอะไรขึ้นมา หากคลาสไม่มีเมธอดอะไรเลยแอตทริบิวต์ภายในออบเจ็กต์ของคลาสนั้นก็ไม่ต่างจาก ตัวแปรธรรมดาที่ไม่ได้ถูกใช้
class ผู้กล้า:
def ถูกโจมตี(self,ความเสียหาย):
self.hp -= ความเสียหาย - self.พลังป้องกัน
เพียงเท่านี้เราก็ได้คลาส
ผู้กล้า
ซึ่งมีเมธอด
ถูกโจมตี
ซึ่งมีไว้สำหรับคำนวณหักลบค่า hp ของผู้กล้าเวลาที่ถูกโจมตีนั่นเอง
ก่อนที่จะอธิบายสิ่งที่เขียนลองมาดูก่อนว่าเมธอดนี้ทำงานยังไง โดยขอยกตัวอย่างการทำงานของเมธอดนี้ด้วยการสร้างผู้เล่นขึ้นมาคนหนึ่งแล้ว ป้อนค่า hp และพลังป้องกันให้ จากนั้นก็ลองใช้เมธอด
ถูกโจมตี
ผู้เล่น3 = ผู้กล้า()
ผู้เล่น3.hp = 35
ผู้เล่น3.พลังป้องกัน = 30
ผู้เล่น3.ถูกโจมตี(40)
print(ผู้เล่น3.hp) # ได้ 25
ผู้เล่น3.ถูกโจมตี(45)
print(ผู้เล่น3.hp) # ได้ 10
จากตัวอย่างนี้จะเห็นว่า
ผู้เล่น3
เป็น
ผู้กล้า
คนหนึ่ง ซึ่งถูกป้อนค่าให้มี hp เป็น 35 และพลังป้องกันเป็น 30
จากนั้นก็สมมุติว่า
ผู้เล่น3
ไปสู้กับปีศาจแล้วโดนโจมตีได้รับความเสียหาย 40 จึงใช้เมธอด
ถูกโจมตี
โดยใส่อาร์กิวเมนต์เป็น 40
ค่า 40 นี้จะกลายเป็น
ความเสียหาย
ซึ่งจะถูกนำไปลบกับ
พลังป้องกัน
กลายเป็น 40-30=10 จากนั้นค่านี้ก็จะนำไปหักลบ hp ดังนั้น hp จึงกลายเป็น 35-10=25 ซึ่งค่านี้ก็จะถูก
print
ออกมา
จากนั้น
ผู้เล่น3
ก็ถูกโจมตีอีกครั้งคราวนี้ 45 ก็ใช้เมธอด
ถูกโจมตี
อีกครั้ง แต่คราวนี้ hp จะลด 45-30=15 จึงเหลือ hp เป็น 25-15=10
เมื่อเข้าใจการทำงานของเมธอดนี้แล้ว ต่อไปจะเริ่มอธิบายโค้ดในส่วนของการประกาศเมธอดว่าที่เขียนไปนั้นหมายความว่าอย่างไร
โครงสร้างจะเห็นว่าคล้ายการนิยามฟังก์ชัน คือใช้
def
ตามด้วยชื่อเมธอด แล้วก็วงเล็บซึ่งภายในวงเล็บมีพารามิเตอร์อยู่
แต่จะมีความยุ่งยากมากกว่าฟังก์ชันอีกหน่อยตรงที่ว่าพารามิเตอร์ตัวแรกสุดที่ ต้องใส่ในการนิยามเมธอดนั้นจะมีสถานะที่ค่อนข้างพิเศษ คือเป็นตัวแปรที่มีไว้สำหรับแทนตัวออบเจ็กต์เอง
โดยทั่วไปแล้วพารามิเตอร์ตัวแรกที่เอาไว้ใช้แทนตัวออบเจ็กต์เองนี้จะถูกเขียนแทนด้วยคำว่า
self
อย่างไรก็ตามจริงๆแล้วนี่เป็นเพียงธรรมเนียมปฏิบัติที่ยึดถือกันมาเท่านั้น ถึงจะใช้คำอื่นแทน
self
ก็ให้ผลเหมือนกัน เช่นลองเขียนใหม่เป็น
class ผู้กล้า:
def ถูกโจมตี(ตัวเอง,ความเสียหาย):
ตัวเอง.hp -= ความเสียหาย - ตัวเอง.พลังป้องกัน
แบบนี้ก็จะให้ผลไม่ต่างกัน อย่างไรก็ตามนี่เป็นธรรมเนียมปฏิบัติที่ค่อนข้างจะตายตัว ดังนั้นในที่นี้ก็จะขอใช้เป็น
self
ด้วย จะไม่มีการใช้คำอื่นแทน
จากนั้นพารามิเตอร์ตัวต่อไปก็จะเป็นตัวแปรทั่วไปซึ่งรับค่าจากค่าที่เราใส่ไว้ในวงเล็บหลังชื่อเมธอดตอนที่เรียกใช้นั่นเอง
จะเห็นว่าตอนที่เรียกใช้นั้นพิมพ์เป็น
ผู้เล่น3.ถูกโจมตี(40)
จะสังเกตได้ว่ามีการใส่อาร์กิวเมนต์แค่ตัวเดียวเท่านั้นคือ 40 ซึ่งถูกนำไปแทนค่าพารามิเตอร์
ความเสียหาย
ซึ่งเป็นพารามิเตอร์ตัวที่สอง
ส่วนพารามิเตอร์ตัวแรกคือ
self
นั้นจะแทนตัวออบเจ็กต์ที่ถูกเรียกใช้เมธอด ซึ่งในที่นี้ก็คือ
ผู้เล่น3
ดังนั้นบรรทัดต่อมาซึ่งเป็นเนื้อหาของเมธอด คือสิ่งที่ต้องการให้มีการทำเมื่อมีการเรียกใช้เมธอดนี้
self.hp -= ความเสียหาย - self.พลังป้องกัน
นี้จึงให้ผลเหมือนการพิมพ์ว่า
ผู้เล่น3.hp -= ความเสียหาย - ผู้เล่น3.พลังป้องกัน
ซึ่งก็จะเป็น
ผู้เล่น3.hp -= 40-30
ดังนั้น hp ของ
ผู้เล่น3
จึงลดลงไป 10 นั่นเอง
ให้สังเกตว่า hp กับ
พลังป้องกัน
จะมี
self.
นำหน้าเพราะทั้งสองค่านี้เป็นแอตทริบิวต์ของออบเจ็กต์ ส่วน
ความเสียหาย
เป็นตัวแปรที่รับค่าเข้ามา ไม่ได้เกี่ยวข้องกับออบเจ็กต์ จึงไม่ต้องใส่
self.
อนึ่ง การเรียกใช้เมธอดอาจเรียกใช้โดย
ชื่อคลาส.ชื่อเมธอด(ออบเจ็กต์,อาร์กิวเมนต์อื่นๆ)
ซึ่งในตัวอย่างนี้จะเขียนเป็น
ผู้กล้า.ความเสียหาย(ผู้เล่น3,40)
ซึ่งความจริงแล้วการเขียนแบบนี้อาจเห็นภาพชัดกว่าด้วย เพราะอาร์กิวเมนต์ตัวแรกคือตัวออบเจ็กต์ ซึ่งจะถูกแทนด้วยพารามิเตอร์
self
ในเมธอด
ดังนั้นก็ต้องจำไว้ว่าหากเมธอดตามหลังคลาสจะต้องมีออบเจ็กต์ เป็นอาร์กิวเมนต์ตัวแรก แต่ถ้าหากเมธอดตามหลังออบเจ็กต์จะไม่ต้องใส่ตัวออบเจ็กต์ลงในอาร์กิวเมนต์ซ้ำอีก ไม่ว่าจะเขียนแบบไหนผลก็คือเมธอดนั้นทำกับตัวออบเจ็กต์
เมธอดจะสร้างกี่อันก็ได้ ถ้าจะเพิ่มเมธอดอีกก็เขียน
def
อีกอัน เช่นคราวนี้ลองเพิ่มเมธอด
ฟื้นพลัง
เอาไว้ใช้เวลาที่ได้รับคาถาฟื้นพลังหรือกินยาฟื้นพลัง
class ผู้กล้า:
def ถูกโจมตี(self,ความเสียหาย):
self.hp -= ความเสียหาย - self.พลังป้องกัน
def ฟื้นพลัง(self,พลังฟื้นฟู):
self.hp += พลังฟื้นฟู
จะเห็นว่าเมธอด
ฟื้นพลัง
ก็คล้ายๆเมธอด
ถูกโจมตี
แต่เรียบง่ายกว่า เพราะฟื้นเท่าไหร่ก็บวก hp ไปเท่านั้นเอย
แต่ทีนี้หากลองนึกถึงในสถานการณ์จริงแล้วผู้เล่นโดยทั่วไปจะต้องมีค่า hp สูงสุดอยู่ ต่อให้ฟื้นพลังแค่ไหนก็ไม่ควรเกินนั้น ดังนั้นควรจะกำหนดเงื่อนไขเพิ่มเติมไปด้วย
รวมถึงเวลาที่ถูกโจมตี ค่า hp ก็ไม่ควรจะลดต่ำกว่า 0 จะกลายเป็นติดลบ และถ้าพลังป้องกันมากกว่าความเสียหายจะกลายเป็น hp เพิ่มแทน ซึ่งไม่ควรจะเกิดขึ้น ควรจะให้เป็น hp ลบ 1 แทน
ดังนั้นควรเขียนใหม่เป็น
class ผู้กล้า:
def ถูกโจมตี(self,ความเสียหาย):
if(ความเสียหาย>self.พลังป้องกัน()):
self.hp -= ความเสียหาย - self.พลังป้องกัน
else:
self.hp -= 1
if(self.hp<0):
self.hp = 0
def ฟื้นพลัง(self,พลังฟื้นฟู):
self.hp += พลังฟื้นฟู
if(self.hp>self.hpสูงสุด):
self.hp = self.hpสูงสุด
เท่านี้เวลาถูกโจมตี hp ก็ไม่มีทางต่ำกว่า 0 และเวลาฟื้นพลังก็จะไม่มีทางเกิน hp สูงสุด
แต่แน่นอนว่าจำเป็นต้องกำหนดค่า
hpสูงสุด
ให้กับผู้กล้าด้วย ไม่เช่นนั้นเมื่อเรียกใช้เมธอด
ฟื้นพลัง
ก็จะขัดข้องทันที
ต้องระวังว่าก่อนที่จะเรียกใช้เมธอด จะต้องกำหนดค่าให้กับแอตทริบิวต์ที่จะเกี่ยวข้องกับเมธอดนั้นทั้งหมดให้เรียบร้อยก่อนแล้ว
ตัวแปรแทนคลาส สิ่งที่อาจต้องระวังอีกอย่างคือเวลาที่สร้างออบเจ็กต์จากคลาสจำเป็นจำต้องใส่วงเล็บเปิดปิดไว้ข้างหลังชื่อคลาสเสมอ เพราะไม่เช่นนั้นแทนที่จะเป็นการสร้างออบเจ็กต์ขึ้น แต่กลับจะกลายเป็นการสร้างตัวแปลใหม่ที่ใช้แทนคลาสแทน
เช่นถ้าพิมพ์เป็นว่า
ก = ผู้กล้า
print(ก) # ได้ <class '__main__.ผู้กล้า'>
จะเห็นว่า
ก
กลายเป็นตัวคลาส
ผู้กล้า
ไปเสียแล้ว
และถ้าเอาไปใช้เพื่อสร้างออบเจ็กต์ขึ้นใหม่อีกทีจะเป็นยังไง ลองดู
ผู้เล่น3 = ก()
print(type(ผู้เล่น3)) # ได้ <class '__main__.ผู้กล้า'>
จะเห็นว่า
ก
ถูกใช้แทน
ผู้กล้า
เพื่อใช้สร้างคลาสขึ้น แต่ว่าคลาสที่สร้างขึ้นมานั้นก็ยังเป็นคลาส
ผู้กล้า
อยู่
เมธอด __init__ โดยปกติแล้วเมธอดจะตั้งเป็นชื่ออะไรก็ได้ อย่างไรก็ตามมีเมธอดอยู่จำพวกหนึ่งที่ค่อนข้างจะพิเศษสักหน่อยคือจะไม่ได้ ทำงานแค่เมื่อเมธอดนั้นถูกเรียกใช้โดยตรงแต่จะทำในบางกรณีที่จำเพาะด้วย
เมธอดพิเศษจะขึ้นต้นและลงท้ายด้วย
__
คือเครื่องหมายขีดล่างสองตัว ในจำนวนนั้นเมธอดพิเศษที่ใช้บ่อยที่สุดก็คือ
__init__
__init__
เป็นเมธอดที่จะทำงานทันทีที่ออบเจ็กถูกประกาศสร้างขึ้นจากคลาส
ตัวอย่างการใช้งาน
class ผู้กล้า:
def __init__(self):
print('ผู้กล้าได้ถือกำเนิดขึ้นแล้ว')
ลองใช้งานดูโดยประกาศสร้างผู้กล้า
ผู้เล่น4 = ผู้กล้า()
เสร็จแล้วก็จะมีข้อความ "ผู้กล้าได้ถือกำเนิดขึ้นแล้ว" ปรากฏขึ้นมา
จะเห็นว่าเราไม่ได้เรียกเมธอด
__init__()
โดยตรง แค่สร้างออบเจ็กต์ขึ้นมาเมธอด
__init__()
ก็ทำงานแล้ว
แน่นอนว่าเราสามารถเรียกใช้มันโดยตรงโดยพิมพ์ชื่อเมธอดได้เช่นกัน เช่น
ผู้เล่น4.__init__()
เมธอด
__init__
ก็เช่นเดียวกับเมธอดทั่วไปๆ คือจะต้องมีพารามิเตอร์อย่างหน่อยหนึ่งตัว โดยที่ตัวแรกคือตัวแปรที่แทนตัวออบเจ็กต์เอง (ซึ่งก็คือ
self
)
โดยทั่วไปแล้วเวลาที่สร้างคลาสมักจะมีการประกาศเมธอด
__init__
ด้วย โดยมักจะเอาไว้ใช้เพื่อกำหนดค่าเริ่มต้นให้กับออบเจ็กต์ที่ถูกสร้างจากคลาส
ตัวอย่างการใช้ เช่น
class ผู้กล้า:
def __init__(self,ชื่อ,เลเวล,พลังโจมตี,พลังป้องกัน,hpสูงสุด):
self.ชื่อ = ชื่อ
self.เลเวล = เลเวล
self.พลังโจมตี = พลังโจมตี
self.พลังป้องกัน = พลังป้องกัน
self.hpสูงสุด = hpสูงสุด
self.hp = hpสูงสุด
print('ผู้กล้าได้ถือกำเนิดขึ้นแล้ว')
จากนั้นเวลาที่จะสร้าง
ผู้กล้า
ขึ้นมาก็จะจำเป็นต้องใส่อาร์กิวเมนต์ไปด้วย ซึ่งก็จะกลายมาเป็นค่าเริ่มต้น
ผู้เล่น4 = ผู้กล้า('ยืนยัน',1,5,6,20)
หรือจะเขียนในรูปแบบคีย์เวิร์ดก็ได้เช่นกัน
ผู้เล่น4 = ผู้กล้า(ชื่อ='ยืนยัน',เลเวล=1,พลังโจมตี=5,พลังป้องกัน=6,hpสูงสุด=20)
อนึ่ง ในที่นี้จะเห็นว่าชื่อพารามิเตอร์ถูกตั้งให้ตรงกับชื่อแอตทริบิวต์ เช่น
self.เลเวล = เลเวล
แต่ความจริงแล้วไม่จำเป็นต้องตรงกันก็ได้ เช่น
self.hp = hpสูงสุด
ซึ่งตรงนี้คือรับค่า
hpสูงสุด
มาแต่ถือโอกาสกำหนดค่า hp ตอนเริ่มต้นเป็นค่า
hpสูงสุด
ไปด้วย
ผลที่ได้ก็จะได้ว่า
ผู้เล่น4
นั้น
ชื่อ
"ยืนยัน"
เลเวล
1
พลังโจมตี
5
พลังป้องกัน
6
hpสูงสุด
20
การทำแบบนี้สะดวกกว่าการที่จะต้องมาค่อยๆป้อนค่าให้แอตทริบิวต์ทีละตัว เพราะถ้าเป็นแบบเดิมจะต้องพิมพ์
ผู้เล่น4.ชื่อ = 'ยืนยัน'
ผู้เล่น4.เลเวล = 1
ผู้เล่น4.พลังโจมตี = 5
ผู้เล่น4.พลังป้องกัน = 6
ผู้เล่น4.hpสูงสุด = 20
ผู้เล่น4.hp = ผู้เล่น4.hpสูงสุด
แต่พอใช้
__init__
ก็แค่ใส่ค่าเป็นอาร์กิวเมนต์ ค่านี้ก็จะถูกนำมาป้อนให้กับแอตทริบิวต์ทันที
เพียงแต่พอทำแบบนี้แล้วจะกลายเป็นว่าต้องคอยใส่ค่าทั้งหมดทุกครั้งที่สร้างออบเจ็กต์ ซึ่งก็เป็นสิ่งที่ควรทำอยู่แล้วเพราะเป็นการบังคับว่าออบเจ็กต์ในคลาสนี้จะต้องมีแอตทริบิวต์อะไรบ้างตั้งแต่ตอนเริ่มสร้าง
แต่ในบางครั้งเราก็อาจจะไม่จำเป็นต้องมาใส่ค่าของแอตทริบิวต์ทั้งหมด ในกรณีแบบนั้นก็อาจใช้การตั้งค่าเริ่มต้น
class ผู้กล้า:
def __init__(self,ชื่อ,เลเวล=1,พลังโจมตี=4,พลังป้องกัน=4,hpสูงสุด=10):
self.ชื่อ = ชื่อ
self.เลเวล = เลเวล
self.พลังโจมตี = พลังโจมตี
self.พลังป้องกัน = พลังป้องกัน
self.hpสูงสุด = hpสูงสุด
self.hp = hpสูงสุด
print('ผู้กล้าได้ถือกำเนิดขึ้นแล้ว')
พอทำแบบนี้แล้วก็จะไม่จำเป็นต้องใส่ค่า
เลเวล
,
พลังโจมตี
,
พลังป้องกัน
และ
hpสูงสุด
ถ้าไม่ใส่ก็จะได้ค่าเป็นค่าเป็น 1,4,4,10 ตามลำดับ แต่ถ้าใส่ก็จะได้ค่าตามที่ใส่
เช่น
ผู้เล่น5 = ผู้กล้า(ชื่อ='มั่นคง',พลังโจมตี=7)
แบบนี้ก็จะได้
ผู้เล่น5
ที่
ชื่อ
"มั่นคง"
เลเวล
1
พลังโจมตี
7
พลังป้องกัน
4 และ
hpสูงสุด
10
เมธอดพิเศษนอกจาก
__init__
แล้วก็ยังมีอีกหลายตัว จะแนะนำเพิ่มเติมใน
บทที่ ๒๔ ใช้ออบเจ็กต์จากคลาสที่สร้างขึ้นเป็นแอตทริบิวต์ ในตัวอย่างที่ผ่านๆมาแอตทริบิวต์เป็นตัวแปรธรรมดาที่คุ้นเคยกันดีเช่นตัวเลข และสายอักขระ แต่แน่นอนว่าแอตทริบิวต์จะเป็นออบเจ็กต์อะไรก็ได้ รวมถึงออบเจ็กต์ในคลาสที่เราสร้างขึ้นมาเองด้วย
ดังนั้นคราวนี้ลองมาสร้างคลาสใหม่ขึ้นอีกคลาสเพื่อใช้เป็นแอตทริบิวต์ในอีกคลาสหนึ่งกันดู
ลองสร้างคลาส
อาวุธ
ขึ้นมา โดยให้เป็นของอย่างหนึ่งที่
ผู้กล้า
ถือครองอยู่ อาวุธนั้นมีคุณสมบัติ
พลังโจมตีกายภาพ
อยู่ ซึ่งจะเป็นตัวกำหนดพลังโจมตีรวมของผู้เล่น
ในตัวอย่างก่อนหน้านี้เราให้
พลังโจมตี
เป็นแอตทริบิวต์หนึ่งของ
ผู้กล้า
แต่คราวนี้จะลองเปลี่ยนใหม่โดยให้
พลังโจมตี
คำนวณจาก
ความแข็งแรง
และ
พลังโจมตีกายภาพ
ของ
อาวุธ
class อาวุธ:
def __init__(self,ชื่อ,พลังโจมตีกายภาพ,พลังโจมตีเวทย์,ความทนทาน):
self.ชื่อ = ชื่อ
self.พลังโจมตีกายภาพ = พลังโจมตีกายภาพ
self.พลังโจมตีเวทย์ = พลังโจมตีเวทย์
self.ความทนทาน = ความทนทาน
class ผู้กล้า:
def __init__(self,ชื่อ,เลเวล=1,ความแข็งแรง=4,พลังป้องกัน=4,hpสูงสุด=10):
self.ชื่อ = ชื่อ
self.เลเวล = เลเวล
self.ความแข็งแรง = ความแข็งแรง
self.พลังป้องกัน = พลังป้องกัน
self.hpสูงสุด = hpสูงสุด
self.hp = hpสูงสุด
def พลังโจมตี(self):
return self.ความแข็งแรง + self.อาวุธที่ถือ.พลังโจมตีกายภาพ
# เริ่มการใช้งาน
ผู้เล่น5 = ผู้กล้า('มั่นคง',1,7,6,15)
ดาบ1 = อาวุธ('ดาบเก่าขึ้นสนิม',6,0,10)
ผู้เล่น5.อาวุธที่ถือ = ดาบ1
print(ผู้เล่น5.อาวุธที่ถือ.ชื่อ) # ได้ ดาบเก่าขึ้นสนิม
print(ผู้เล่น5.อาวุธที่ถือ.พลังโจมตีกายภาพ) # ได้ 6
print(ผู้เล่น5.อาวุธที่ถือ.พลังโจมตีเวทย์) # ได้ 0
print(ผู้เล่น5.อาวุธที่ถือ.ความทนทาน) # ได้ 10
print(ผู้เล่น5.พลังโจมตี()) # ได้ 13
จากตัวอย่างนี้จะเห็นว่ามีการสร้าง
ดาบ1
ขึ้นเป็นออบเจ็กต์ในคลาส
อาวุธ
มีแอตทริบิวต์
ชื่อ
,
พลังโจมตีกายภาพ
,
พลังโจมตีเวทย์
,
ความทนทาน
ซึ่งต้องกำหนดค่าตอนที่สร้างออบเจ็กต์ขึ้น
จากนั้นก็ให้
ผู้เล่น5
ถือ
ดาบ1
ด้วยการตั้งให้แอตทริบิวต์
อาวุธที่ถือ
ของ
ผู้เล่น5
เป็น
ดาบ1
พอแอตทริบิวต์
อาวุธที่ถือ
ของ
ผู้เล่น5
กลายเป็น
ดาบ1
ไปแล้วแบบนี้แอตทริบิวต์ของอาวุธก็กลายเป็นแอตทริบิวต์ของแอตทริบิวต์ เราสามารถเข้าถึงได้ด้วยการใส่จุด
.
สองต่อดังที่เห็น
และสุดท้าย เราได้ใช้เมธอดที่สร้างขึ้นมาใหม่ เมธอด
พลังโจมตี
ซึ่งจะคืนค่าพลังโจมตีของผู้เล่นออกมา โดยคำนวณจาก
ความแข็งแรง
ซึ่งเป็นแอตทริบิวต์ของผู้เล่นเอง บวกกับ
พลังโจมตีกายภาพ
ของ
อาวุธที่ถือ
ที่ผู้เล่นถืออยู่
ให้สังเกตว่า
พลังโจมตี
ในตัวอย่างนี้ต่างจากตัวอย่างที่ผ่านมา คือพลังโจมตีไม่ได้เป็นแอตทริบิวต์แล้วแต่กลายเป็นเมธอด ทำให้ต้องมีวงเล็บเปิดปิด
()
ต่อท้ายด้วย
นั่นเพราะในกรณีนี้เราไม่ได้เก็บค่าพลังโจมตีของผู้กล้าเอาไว้เป็นตัวแปรหนึ่งแล้วแต่เปลี่ยนให้มัน เป็นค่าที่ได้จากการคำนวณโดยรวมความแข็งแรงกับพลังโจมตีกายภาพของอาวุธแทน
การทำแบบนี้มีข้อดี แทนที่จะต้องมาเก็บค่าพลังโจมตีไว้เป็นตัวแปรอีกตัวหนึ่ง พอให้เป็นเมธอดแบบนี้แล้วพอผู้กล้ามีค่าความแข็งแรงเปลี่ยนแปลงไปหรือ เปลี่ยนอาวุธใหม่ก็ไม่ต้องมาแก้ค่าพลังโจมตีตาม เพราะสามารถคำนวณออกมาได้ทันทีแค่เรียกใช้เมธอด
ต่อไปลองเพิ่มคลาสและเมธอดลงไปให้หลากหลายขึ้นดู
class อาวุธ:
def __init__(self,ชื่อ,พลังโจมตีกายภาพ,พลังโจมตีเวทย์,ความทนทาน):
self.ชื่อ = ชื่อ
self.พลังโจมตีกายภาพ = พลังโจมตีกายภาพ
self.พลังโจมตีเวทย์ = พลังโจมตีเวทย์
self.ความทนทาน = ความทนทาน
class เสื้อผ้า:
def __init__(self,ชื่อ,พลังป้องกัน,ความทนทาน):
self.ชื่อ = ชื่อ
self.พลังป้องกัน = พลังป้องกัน
self.ความทนทาน = ความทนทาน
class ผู้กล้า:
def __init__(self,ชื่อ,เลเวล=1,ความแข็งแรง=4,พลังเวทย์=4,ความอดทน=4,hpสูงสุด=10):
self.ชื่อ = ชื่อ
self.เลเวล = เลเวล
self.ความแข็งแรง = ความแข็งแรง
self.พลังเวทย์ = พลังเวทย์
self.ความอดทน = ความอดทน
self.hpสูงสุด = hpสูงสุด
self.hp = hpสูงสุด
def พลังโจมตี(self):
return self.ความแข็งแรง + self.อาวุธที่ถือ.พลังโจมตีกายภาพ
def พลังโจมตีเวทย์(self):
return self.พลังเวทย์ + self.อาวุธที่ถือ.พลังโจมตีเวทย์
def พลังป้องกัน(self):
return self.ความอดทน + self.เสื้อผ้าที่ใส่.พลังป้องกัน
def ถูกโจมตี(self,ความเสียหาย):
if(ความเสียหาย>self.พลังป้องกัน()):
self.hp -= ความเสียหาย - self.พลังป้องกัน()
else:
self.hp -= 1
if(self.hp<0):
self.hp = 0
# เริ่มการใช้งาน
ผู้เล่น6 = ผู้กล้า('กระสัน',1,4,8,6,15)
คฑา1 = อาวุธ('คฑาเก่าผุๆ',1,6,10)
เกราะ1 = เสื้อผ้า('เกราะเก่าผุๆ',4,10)
ผู้เล่น6.อาวุธที่ถือ = คฑา1
ผู้เล่น6.เสื้อผ้าที่ใส่ = เกราะ1
print(ผู้เล่น6.อาวุธที่ถือ.ชื่อ) # ได้ คฑาเก่าผุๆ
print(ผู้เล่น6.เสื้อผ้าที่ใส่.ชื่อ) # ได้ เกราะเก่าผุๆ
print(ผู้เล่น6.พลังโจมตี()) # ได้ 5
print(ผู้เล่น6.พลังโจมตีเวทย์()) # ได้ 14
print(ผู้เล่น6.พลังป้องกัน()) # ได้ 10
ในที่นี้ได้เพิ่ม
เสื้อผ้าที่ใส่
มาเพื่อใช้เป็นตัวคำนวณพลังป้องกัน โดยมีการกำหนดให้
ผู้กล้า
มีแอตทริบิวต์
ความอดทน
ด้วย พลังป้องกันในที่นี้กำหนดให้เป็นเมธอดที่คำนวณผลรวมของ
ความอดทน
และ
พลังป้องกัน
ของเสื้อผ้า
นอกจากนี้ยังได้เพิ่มเมธอด
พลังโจมตีเวทย์
ซึ่งคำนวณจาก
พลังโจมตีเวทย์
ของ
อาวุธที่ถือ
บวกกับ
พลังเวทย์
ของ
ผู้กล้า
ในที่นี้จะคฑาหรือดาบก็กำหนดให้เป็นอาวุธเหมือนกัน มีพลังโจมตีกายภาพและเวทย์เหมือนกันเพียงแต่ค่าจะสูงต่ำต่างกันเท่านั้น
แน่นอนว่าจะกำหนดให้เป็นคนละคลาสกันก็ได้เช่นแบ่งเป็น
อาวุธกายภาพ
กับ
อาวุธเวทย์
ก็แล้วแต่ความสะดวก อาจลองทำดูได้ แต่ในที่นี้คิดว่ายังไม่มีความจำเป็นต้องแบ่ง
และสุดท้าย ใส่เมธอด
ถูกโจมตี
ไปด้วย โดยเขียนคล้ายกับเมธอดก่อนหน้านี้ ต่างกันแค่
พลังป้องกัน
ในที่นี้ใช้เป็นเมธอดแล้วจึงต้องใส่วงเล็บ
()
ไว้ข้างหลัง
ตัวแปรในคลาส หากมีการประกาศตัวแปรภายในคลาส ตัวแปรนั้นจะเรียกว่าเป็นตัวแปรในคลาส ทุกออบเจ็กต์ที่เป็นอินสแตนซ์ของคลาสนั้นจะมีค่าตัวแปรนั้นติดตัวอยู่
ลองใส่ตัวแปรคลาสให้กับคลาส
ผู้กล้า
ดู เช่นผู้กล้าแต่ละคนก็น่าจะมี
เงินเดือน
ให้สักหน่อย
class ผู้กล้า:
def __init__(self,ชื่อ,เลเวล=1,ความแข็งแรง=4,ความอดทน=4,hpสูงสุด=10):
self.ชื่อ = ชื่อ
self.เลเวล = เลเวล
self.ความแข็งแรง = ความแข็งแรง
self.ความอดทน = ความอดทน
self.hpสูงสุด = hpสูงสุด
self.hp = hpสูงสุด
เงินเดือน = 500
พอทำแบบนี้แล้วก็จะได้ว่าออบเจ็กต์ในคลาส
ผู้กล้า
ทุกคนจะมีแอตทริบิวต์
เงินเดือน
ซึ่งมีค่า 500
พูดสั้นๆคือ
ผู้กล้า
ทุกคนมี
เงินเดือน
เป็น 500
แต่ไม่ใช่แค่นั้น ตัวคลาสเองก็มีค่าแอตทริบิวต์นี้เช่นกัน ลองดูตัวอย่าง
print(ผู้กล้า.เงินเดือน) # ได้ 500
ผู้เล่น7 = ผู้กล้า('มั่งมี')
print(ผู้เล่น7.เงินเดือน) # ได้ 500
ผู้เล่น8 = ผู้กล้า('เป็นสุข')
print(ผู้เล่น8.เงินเดือน) # ได้ 500
ผู้เล่น7
และ
ผู้เล่น8
เป็นอินสแตนซ์ของคลาส
ผู้กล้า
จึงมีแอตทริบิวต์
เงินเดือน
เป็น 500 และตัวคลาส
ผู้กล้า
เองก็มีแอตทริบิวต์ 500 เช่นกัน
แอตทริบิวต์ของคลาสสามารถเปลี่ยนแปลงได้หลังจากประกาศคลาสแล้ว สมมุติว่า
ผู้กล้า
ถูกประกาศลดเงินเดือนทั้งหมด
ผู้กล้า.เงินเดือน = 400
print(ผู้เล่น7.เงินเดือน) # ได้ 400
print(ผู้เล่น8.เงินเดือน) # ได้ 400
print(ผู้กล้า.เงินเดือน) # ได้ 400
จะเห็นว่าพอเปลี่ยนค่า
เงินเดือน
ซึ่งเป็นแอตทริบิวต์ของคลาส
เงินเดือน
ของออบเจ็กต์ในคลาสก็เปลี่ยนตาม
อย่างไรก็ตาม หากเราป้อนค่าแอตทริบิวต์ให้
ผู้เล่น7
แอตทริบิวต์
เงินเดือน
จะกลายเป็นแอตทริบิวต์ของออบเจ็กต์แทน ค่านั้นจะไม่มีผลต่อแอตทริบิวต์ของคลาสหรือออบเจ็กต์อื่น
เช่น สมมุติว่า
ผู้เล่น7
ทำผลงานดีเลยได้ขึ้นเงินเดือน ลองประกาศเพิ่มเงินเดือนให้กับ
ผู้เล่น7
คนเดียว
ผู้เล่น7.เงินเดือน = 3000
print(ผู้เล่น7.เงินเดือน) # ได้ 3000
print(ผู้เล่น8.เงินเดือน) # ได้ 400
print(ผู้กล้า.เงินเดือน) # ได้ 400
จะเห็นว่าใส่ค่า 3000 ให้กับ
เงินเดือน
ของ
ผู้เล่น7
จึงทำให้เพิ่มอยู่แค่คนเดียว ผิดกับกรณีที่เปลี่ยนค่าให้กับ
เงินเดือน
ของ
ผู้กล้า
ซึ่งเป็นการเปลี่ยนค่าแอตทริบิวต์ของคลาส แบบนี้จะถูกเปลี่ยนแปลงทั้งหมด
แล้วในตอนนี้หากลองเปลี่ยนค่า
เงินเดือน
ของ
ผู้กล้า
อีกครั้งจะเกิดอะไรขึ้น? ก็จะพบว่า
เงินเดือน
ของ
ผู้เล่น7
ไม่มีการเปลี่ยนแปลงใดๆ แต่ของ
ผู้เล่น8
จะยังเปลี่ยนแปลงตามอยู่
ผู้กล้า.เงินเดือน = 600
print(ผู้เล่น7.เงินเดือน) # ได้ 3000
print(ผู้เล่น8.เงินเดือน) # ได้ 600
print(ผู้กล้า.เงินเดือน) # ได้ 600
ที่เป็นแบบนี้เพราะ
เงินเดือน
ของ
ผู้เล่น7
ได้กลายเป็นแอตทริบิวต์ของตัวออบเจ็กต์เองไปแล้ว ไม่ใช่แอตทริบิวต์ของคลาสอีกต่อไป ดังนั้นต่อให้เปลี่ยนค่าแอตทริบิวต์ของคลาสก็จะไม่เปลี่ยนแปลงตาม
แต่ของ
ผู้เล่น8
ยังไม่มีการป้อนค่าแอตทริบิวต์
เงินเดือน
ให้ ดังนั้นแอตทริบิวต์
เงินเดือน
ก็ยังเป็นแอตทริบิวต์ของคลาสอยู่
ในตอนนี้ถ้ามีการสร้างออบเจ็กต์ในคลาสขึ้นมาใหม่ก็จะได้ค่าเงินที่เปลี่ยนแปลงไปแล้วนี้เช่นกัน
ผู้เล่น9 = ผู้กล้า('พอใจ')
print(ผู้เล่น9.เงินเดือน) # ได้ 600
สรุปแล้วก็คือเราอาจใช้แอตทริบิวต์ของคลาสเป็นค่าเริ่มต้นให้กับออบเจ็กต์ของคลาสนั้นทั้งหมดตอนเริ่มแรก ถ้าหากมีการใส่ค่าแอตทริบิวต์ให้ออบเจ็กต์นั้นโดยจำเพาะจึงค่อยเปลี่ยนมัน เป็นแอตทริบิวต์ของตัวออบเจ็กต์
ลองใช้กับอย่างอื่น เช่นกำหนด
อาวุธ
กับ
เสื้อผ้า
ให้กับผู้เล่นเริ่มต้น
class อาวุธ:
def __init__(self,ชื่อ,พลังโจมตีกายภาพ,พลังโจมตีเวทย์,ความทนทาน):
self.ชื่อ = ชื่อ
self.พลังโจมตีกายภาพ = พลังโจมตีกายภาพ
self.พลังโจมตีเวทย์ = พลังโจมตีเวทย์
self.ความทนทาน = ความทนทาน
class เสื้อผ้า:
def __init__(self,ชื่อ,พลังป้องกัน,ความทนทาน):
self.ชื่อ = ชื่อ
self.พลังป้องกัน = พลังป้องกัน
self.ความทนทาน = ความทนทาน
class ผู้กล้า:
def __init__(self,ชื่อ,เลเวล=1,ความแข็งแรง=4,ความอดทน=4,hpสูงสุด=10):
self.ชื่อ = ชื่อ
self.เลเวล = เลเวล
self.ความแข็งแรง = ความแข็งแรง
self.ความอดทน = ความอดทน
self.hpสูงสุด = hpสูงสุด
self.hp = hpสูงสุด
อาวุธที่ถือ = อาวุธ('มีดสั้นเก่าๆ',3,0,5)
เสื้อผ้าที่ใส่ = เสื้อผ้า('ชุดเก่าๆ',3,5)
ผู้เล่น10 = ผู้กล้า('มีฤทธิ์')
print(ผู้เล่น10.อาวุธที่ถือ.ชื่อ) # ได้ มีดสั้นเก่าๆ
print(ผู้เล่น10.อาวุธที่ถือ.พลังโจมตีกายภาพ) # ได้ 3
print(ผู้เล่น10.เสื้อผ้าที่ใส่.ชื่อ) # ได้ ชุดเก่าๆ
สรุปเนื้อหา
- ออบเจ็กต์จะถูกสร้างขึ้นจากคลาส
- ออบเจ็บต์ถูกสร้างขึ้นจากคลาสไหนจะถูกเรียกว่าเป็นอินสแตนซ์ของคลาสนั้น
- ออบเจ็กต์จะประกอบไปด้วยข้อมูลต่างๆซึ่งถูกเก็บอยู่ภายในแอตทริบิวต์
- ฟังก์ชันที่ประกาศในคลาสจะกลายเป็นเมธอดสำหรับออบเจ็กต์ของคลาสนั้น
- ออบเจ็กต์จะสามารถใช้เมธอดที่นิยามภายในคลาสของมันได้
- ตัวแปรที่ประกาศในคลาสจะกลายเป็นแอตทริบิวต์ของคลาส
- หากตั้งแอตทริบิวต์ของออบเจ็กต์เป็นชื่อเดียวกับแอตทริบิวต์คลาส ชื่อแอตทริบิวต์นั้นจะชี้ไปที่แอตทริบิวต์ของออบเจ็กต์แทน
อ้างอิง