มันมีทั้ง massage, inheritance, polymorphism, encapsulation ใน Python ใช้อย่างไรเหรอครับ
(มีตัวอย่างโต้ดโปรแกรมด้วยจะขอบคุณมากครับ ไม่ใช่งานส่งอ.นะ แค่อกยากรู้จริง)
กระทู้เก่าๆ จะย้ายตามไปในภายหลัง ตอนนี้ปิดการโพสต์กระทู้ไว้ เหลือไว้เฉพาะอ้างอิงเท่านั้น
เรื่องมันยาวครับ oo ใน Python ไม่ค่อยจะสมบูรณ์ ผมก็ไม่เห็นความจำเป็นต้องสมบูรณ์ เรื่องนี้มันขึ้นกับความเชื่อ
อาจฟังดูแปลกๆ ยกตัวอย่างง่ายๆ oo ของ Java บังคับให้ทุกอย่างเป็น oo แล้วหาทางแก้ด้วย
public static void mainซึ่งบางคนไม่เข้าใจ oo ผลออกมาเลยกลายเป็น ทุกเมธทอดเป็น public static กันหมด ซึ่งก็ไม่ใช่ oo ซะแล้ว ใน Python เลยไม่ได้บังคับ ไม่มีคำว่า public protected private มีแต่หลักการซึ่งขึ้นกับความเชื่ออยู่ดีInheritance
เอ นี่ผมยกตัวอย่างถูกรึเปล่าเนี่ย เช้านี้หัวตื้อจัง
Polymorphism
ถ้าเปลี่ยน
Humanข้างบนเป็นแบบนี้แล้วMaleกับFemaleยังเหมือนเดิม ก็ยังทำงานได้อยู่ดี นี่เป็น polymorphism แบบ Pythonเวลาเอาไปใช้ เราสามารถระบุชื่อเพื่อกำหนดค่าได้โดยตรง ค่าที่ไม่ได้ระบุก็จะมีค่าเป็นค่าปริยาย
me = Human('johnny thomson','male',telno='66-2-111-1111')ถ้าอยากให้ยืดหยุ่นสุดๆ ก็ใช้แบบนี้
แปลว่าอะไรก็ตามที่ตามหลัง
genderและไม่ได้ระบุชื่อจะส่งมาเป็น list อยู่ในargsส่วนที่ระบุชื่อทั้งหมดจะอยู่ในkwเป็น dictEncapsulation
ตัวแปรในตัวอย่างข้างบนทั้งหมดถือเป็น public จริงๆ ก็มีแต่ public น่ะแหละ ใน Python จะใช้วิธีตั้งชื่อแทน โดยที่ถ้าชื่อขึ้นต้นด้วย
_แปลว่า protected และ__คือ privateเช่นแต่ในความเป็นจริงไม่มีการปิดกั้นใดๆ ทั้งสิ้น บางคนก็ชอบใช้เพื่อบอกให้รู้ว่า
__อาจจะมีการเปลี่ยนแปลงได้ในอนาคต ส่วน_จะเปลี่ยนน้อยหน่อย นอกนั้นจะไม่เปลี่ยนหรือนานมากๆ ซึ่งก็เป็นแนวคิดของ Encapsulation อยู่แล้ว แต่ถ้าใครตะขิดตะขวงใจว่าไม่มี setter getter ก็มีทางออกให้ด้วยproperty()จากโค้ดข้างบน
nameแก้ไม่ได้genderถูกเช็คก่อนแก้addressกับtelnoเหมือนปกติผมไม่แม่นเรื่อง oo ซักเท่าไหร่ message นี่คืออะไรหว่า ลองอธิบายซักนิดซิครับ ผมจะได้รู้เรื่องกับเค้าบ้าง
รู้สึกว่า Polymorphism จะหมายถึงอย่างอื่นน่ะครับ คือ มันจะหมายถึงว่าการที่ class ลูก สามารถเปลี่ยนพฤติกรรมไปจาก class แม่ได้
ใน Python แนวคิดนี้ไม่ค่อยมีผลเท่าไหร่ เพราะว่า ตัวแปรไม่ได้มี static type ติดตัวไปกับมัน ทำให้เวลาเรียกใช้ method ที่เรา def เอาไว้ มันก็เป็นไปตามตัวแปร
เพื่อให้เห็นภาพ ยกตัวอย่างจาก java แล้วกันครับ สมมติผมมีคลาส Par แล้วก็มีคลาสที่ inherit มาชื่อ Chd ทีนี้ ถ้าใน par มี method m1 แล้วก็ใน chd เขียน method m1 ใหม่ นะครับ ทีนี้ ถ้าผมสั่งประมาณนี้
สังเกตว่าในรอบหลัง จะเรียก method m1 ของ Chd ถึงแม้ว่า static type ของ p จะเป็น Par
ทีนี้ ผมเข้าใจว่าใน Python มันไม่มี static type ของตัวแปรอยู่แล้ว (type จะเหมือนว่าติดไปกับ "ค่า" ของมัน) เวลาเรียก method อะไรมันก็ไปหาเอาจากที่เราประกาศ
ซึ่งมันจะเปิดกว้างกว่าใน Java ซึ่งในกรณีของ Java หรือ C++ เราจะทำได้ถ้า Chd inherit มาจาก Par แต่ใน Python จะเป็นยังไงก็ได้ ไม่จำเป็นต้องมีความสัมพันธ์อะไรกันเลยก็ได้ ลักษณะเช่นนี้จะคล้าย ๆ กับภาษาพวก Smalltalk เสียมากกว่าน่ะครับ
ถ้าต้องเป็นพ่อแม่ลูกกัน เรียกว่า Subtyping polymorphism (แบบ Java ที่อ.jittat กรุณายกตัวอย่างให้ดู)
type polymorphism ทั่วไป ผมเข้าใจว่า method ชื่อเดียวกัน ของต่าง object กันมี definition ต่างกัน แต่ว่าเราเขียนโปรแกรมส่ง message ได้เหมือนเดิม ไม่ว่า method นั้นจะมี definition อย่างไร
จากตัวอย่าง object ชื่อ ticket_boy กับ me มี method ชื่อ travel เหมือนกัน แต่ definition ไม่เหมือนกัน
แต่ว่า yourfunc ส่ง message "travel" (พร้อม argument from:"kaset" to:"the mall") ไปให้ทั้ง ticket_boy กับ me ได้เหมือนกัน โดยไม่ต้องไปเขียน yourfunc_ticketboy หรือ yourfunc_me แยกกันต่่างหาก
แบบ Ruby และ Python นี่เรียก Duck typing ไม่สนใจว่าเป็น พ่อ แม่ ลูก กันหรือเปล่า(แบบ subtyping) ประมาณว่าส่ง message ไปก่อน เดี๋ยว receiver ก็ส่งกลับมาบอกเอง ถ้า receiver ไม่รู้จัก message นั้น มันก็ raise exception มั้ง
เอ้าเหรอ ผมนึกว่า Polymorphism คือการที่ทำให้ method รับพารามิเตอร์ได้หลายแบบ อย่างใน Java ก็มี Constructor ได้หลายตัว เพื่อรับหลายแบบ ส่วน Python ทำแบบนั้นไม่ได้ต้องใช้วิธี keyword argument แทน
อันนั้นเรียก overloading นะ คิดว่า
จาก wikipedia บอกว่า overloading ก็เป็นหนึ่งใน polymorphism พูดง่ายๆ ก็คือเรื่องที่เราพูดๆ กันมามันเป็น polymorphism กันหมด มันเป็นแค่เทคนิคย่อยๆ อืมลึกซึ้งจริงๆ สอบผ่านมาได้ไงหว่า
อืม กว้่างจริงๆ
ถ้าแปลตามตัวคงแปลว่า หลายรูปแบบ
คือ ชื่อเดียว แต่หลายรูปแบบ.... อืม อืม อืม
polymorphism ภายใน object เดียวกัน :-O
ตอนเรียนผมก็ไม่ได้หลับนะครับ ทำไมไม่เห็นรู้เลยอะ lol
(อาจจะเรียนไม่เหมือนกัน)
ตามความเข้าใจของผมนั้น message นั้นคือการคุยกันของ object ต่างๆ นะครับ อาจจะเป็นการเรียก method, การ instantiate, ฯลฯ
พอไปแอบดูใน wikipedia แล้วก็ได้มาอย่างนี้:
In the terminology of some object-oriented languages, a message is the single means to pass control to an object. If the object 'responds' to the message, it has a method for that message.
ที่มา: http://en.wikipedia.org/wiki/Message_%28computer_science%29
ในโลกของ OO เค้าไม่เรียกว่าการ call function น่ะครับ แต่จะมองว่า object ตัวนึงส่ง message ไปหา object อีกตัวนึง แล้ว object ตัวนั้นแปลความหมายของ message นั้นออกมาได้ว่าอย่างไร
อย่างนี้นี่เอง สงสัยตอนเรียนเรื่องนี้จะหลับ ขอบคุณมากครับ
function call นี่ส่วนใหญ่มันก็ต้องมี function นั้นอยู่จริงๆ ใช่เปล่า?
แต่เวลา receiver ได้ message ไป receiver ก็ไม่จำเป็นต้องมี method หรือ function อยู่จริงๆ ก็ได้ แล้วแต่ว่า receiver นั้นอยากจะ respond กับ message นั้นอย่างไร
ลองเล่น Gorm แล้วอาจจะเห็นภาพเรื่องพวกนี้มากขึ้นก็ได้
เรื่องพวกนี้ผมลืมไปเกือบหมดแล้วครับตอนนี้ แหะ ๆ น่าเสียดายเหมือนกัน ได้มาอ่านอีกรอบรู้สึกดีครับ ได้ฟื้นความรู้เก่า ๆ
ผมขอตั้งข้อสังเกตครับว่า คนที่ใช้ภาษา script จนชินจะไม่ค่อยแน่นทฤษฏี OOP มากนัก ผมเนี่ยตัวดีเลย ซึ่งจริง ๆ ก็ไม่ดีหรอกครับ แต่มันก็มีเหตุผลของมันอยู่
ทฤษฏี OOP ต่าง ๆ ในปัจจุบันมักตั้งอยู่บนพื้นฐานของ Java (C++, C# ก็กล้อมแกล้มไปกันได้ ไม่ต่างกันมาก) คุณลักษณะอย่างหนึ่งของ Java คือเป็น Static Type ดังนั้นเลยต้องมีเทคนิคต่าง ๆ มากมายเกิดขึ้น เพื่อให้การทำงานยืดหยุ่นขึ้น
ผมเคยซื้อหนังสือมาอ่านสองเล่ม Software Architecture กับอีกเล่ม รู้จักแต่ชื่อภาษาเยอรมันครับ Entwurt Muster ประมาณว่าการออกแบบพิมพ์เขียวโปรแกรม ทั้งสองเล่นเป็น Java Oriented อ่านผ่าน ๆ จนจบ สรุปใจความได้ว่า จะออกแบบโปรแกรมยังไง ให้ต่อยอดได้โดยไม่มีปัญหา โดยสามารถ reuse โค้ดได้ และยืดหยุ่น ซึ่งสองอย่างนี้มักมาไม่พร้อมกัน ใน Software Architecture เขาเขียนถึงไว้หน่อยนึงครับว่า ภาษาพวก dynamic type มักไม่จำเป็นต้องใช้ทฤษฏีในหนังสือ สิ่งที่สำคัญกว่าคือ Specification, ตัวโครงสร้าง, Customization และ Optimization ซึ่งในภาษา static type ก็มีความสำคัญไม่น้อยไปกว่ากัน แต่หากไม่รู้วิธีเขียนที่ดีพออาจพบทางตันได้ง่ายกว่า
ดังนั้นคนที่เคยชินกับ static type OOP ต้องเปลี่ยนวิธีคิดเยอะพอสมควรครับ
ใช่แล้วๆ ผมเข้าใจว่าจะเป็นพวก Design Patterns
ข้อเสียที่ควรหลีกเลี่ยง มันทำให้ผมปวดหัวมาก คือ multiple inheritance
ปัญหาคือ สืบทอดได้หลายคลาส แล้วถ้าเกิด class A กับ class B มี method ชื่อซ้ำกันเวลาที่ class C(A,B) เนี่ย มันจะใช้ method ของ class ไหน หรือต้องมาระบุชื่อ class นำหน้า method นั้นก่อนหรือเปล่า
ขนาดภาษา D ที่เป็นรุ่นต่อไปของ C++ ยังตัด Multiple Inheritance ออกไปเลย ดูเปรียบเทียบได้ที่นี่ครับ
เขาถึงได้ว่า python มี OOP ที่ยังไม่สมบูรณ์นัก เพราะอิงกับ C++ ซะเยอะไปหน่อย
การมี multiple inheritance ไม่ได้ทำให้ ความเป็น OOP ไม่สมบูรณ์นะครับ
อย่างในภาษา Eiffel (http://en.wikipedia.org/wiki/Eiffel_programming_language) ซึ่งเป็น ISO-standardized object-oriented programming language นั้น นอกเหนือจากเรื่อง Design by contract ที่โด่งดังแล้ว เรื่อง multiple inheritance นั้นเป็นหนึ่งในจุดแข็งของภาษาเลยทีเดียว
ใน Python จะใช้ multiple inheritance สำหรับทำส่วนประกอบแล้วเอามาผสมพันธุ์เพื่อสร้างสัตว์ประหลาดที่มีความสามารถหลากหลาย เช่น เขียนเซิร์ฟเวอร์ธรรมดาขึ้นมา ถ้าอยากทำเป็นเทรดก็แค่ inherit เพิ่มเข้าไปก็จบ บางทีก็เรียก MixIn เรื่องชื่อ method ซ้ำกัน ถ้าเราไม่ทำแบบนั้นก็ไม่มีใครว่านี่ครับ เลี่ยงได้ก็เลี่ยง แต่บางทีผมก็อยากทำ โดยเฉพาะถ้า class แม่เป็นของคนอื่น ก็ต้องจำใจทำเป็นอย่างยิ่ง
ผมมองว่า python โดยความตั้งใจแล้ว ไม่ได้จะพยายามเป็นภาษา OOP อย่างสมบูรณ์แบบมาตั้งแต่แรกแล้ว
ลองดู feature ของภาษาใหม่ๆที่ออกมาใน version หลังๆ มีความพยายามที่จะปรับปรุงเรื่อง OOP บ้างแต่ก็ไม่มาก feature ใหม่ส่วนใหญ่จะกระเดียดไปทาง functional เสียมากกว่า
ในอนาคต ใน python 3000 ก็ไม่ได้พูดถึงความพยายามที่จะทำให้ python เป็น OOP อย่างสมบูรณ์แบบจ๋า
python ก็เป็นอย่างที่เป็นของมัน ซึ่งคนใช้ภาษาก็รักมันอย่างที่มันเป็น
ผมเห็นด้วยกับคุณ work4best และคุณ sugree ว่า multiple inheritance จริง ๆ แล้วเป็นจุดเด่นของภาษาที่มี เช่น C++ เลยทีเดียว
การออกแบบ C++ ที่มีเงื่อนไขหลาย ๆ อย่างเช่น ต้อง compatible กับ C และ efficiency ต้องไม่ตก นั่นคือ ถ้าเขียนโปรแกรมไม่ได้ใช้ feature อะไร ความเร็วของโปรแกรมที่ได้ในภาษาควรจะต้องเท่าเทียมกับในกรณีที่ภาษาไม่มี feature นั้น ๆ ทำให้ C++ เป็นภาษาที่ต้องเรียกว่าออกแบบมาได้ดีมาก ๆ (ยกตัวอย่างเช่นการให้ผู้ใช้กำหนด virtual function เอง ไม่ใช่ว่าจะทำ dynamic look-up ตลอด)
ในกรณีของ multiple inheritance ก็เช่นกัน ถ้าไม่ใช้ โปรแกรมที่ได้ก็ทำงานได้ตามปกติ ถ้าจำเป็นต้องใช้ (เพรา่ะว่าให้ผลลัพธ์/โปรแกรม ที่ดีกว่า) ก็มีให้ใช้ อาจจะปวดหัวบ้าง แต่ก็มีให้ใช้
ภาษาที่ไม่มี multiple inheritance นั้น ผมเข้าใจว่าทำให้การ implement ตัวภาษา (เช่น คอมไพเลอร์) ง่ายขึ้น และโดยทั่วไปก็มักบอกว่า multiple inheritance นั้นไม่จำเป็น "มาก" และมีแนวทางให้พอทำได้อยู่แล้ว เช่นมี interface แยกออกมาจาก class อีกที ซึ่งจริง ๆ ผมมองว่ามันก็คือความพยายามจะทำให้ใช้ความสามารถของ multiple inheritance ได้ โดยไม่จำเป็นต้อง support ทุกอย่างนั่นเอง
แถมลิงก์ครับ
multiple and virtual inheritance จาก C++ FAQ lite
The Virtues of Multiple Inheritance
OOP ที่สมบูรณ์ต้องมีคุณสมบัติอะไรบ้าง?
แฟน Java กับ C++ อาจจะบอกว่า ต้องมี public, private, protected ด้วย?
แฟน smalltalk อาจจะบอกว่าทุกอย่างต้องเป็น object หมด?
ผมอาจจะบอกว่า object ต้องตอบสนอง message ได้แม้ว่า จะไม่มี method ชื่อเดียวกับ message เพราะมันเป็นคนละอย่างกัน ...
ผมคิดว่า Python กับ C++ ห่างกันกว่า Java กับ C++ ซะอีก Python ไม่ได้ใช้ vtable, python ใช้ type แบบ duck type ไม่ได้ใช้ static type แบบ C++ และ Java ฯลฯ multiple inheritance ของ Python อาจจะมาจาก CLOS? ด้วยหรือเปล่าก็ไม่รู้
คนทำ Python เลือก multiple inheritance แทนที่จะจัดระเบียบให้ใช้ได้แต่ Mixin ที่ไม่มี instance variable เหมือน Ruby หรือว่าบังว่าต้องใช้ Interface แบบ Java อาจจะเป็นเพราะแนวความคิดเรื่อง minimalism ที่ syntax ไม่ควรมีรูปแบบหลากหลาย ถ้าเลือกจะทำแบบ Java ก็ต้องมี extend กับ implement จะทำแบบ Ruby ก็ต้องมี < กับ include ถ้าใช้ multiple inheritance ก็มีแต่ inherit อย่างเดียว
cPython นี่วิธีการ lookup นี่ีค่อนข้างขัดเจนนะครับ เข้าใจว่าเพิ่งมาเปลี่ยนเอาตอน 2.5 นี่เอง ก่อนหน้านี้รู้สึกจะใช้ depth-first search ตอนหลังนี่หาข้างบนก่อนเสมอแล้ว (เหมือนจะกำหนดว่าฝั่งขวาก่อนเสมอด้วย)