What is Pythonic?
วันนี้ลองมาอธิบายคำว่า Pythonic กันดีกว่า พอดีมีคนถามที่Codenone แล้วตอนนั้นก็ตอบแบบสั้นๆ ช่วงนี้พอมีเวลาเลยลองมาศึกษาให้ถ่องแท้ดีกว่า ผมเองก็ไม่รู้จะอธิบายยังไงเหมือนกัน คล้ายกับว่า Pythonic เป็นปรัชญาชนิดหนึ่ง เรียบง่าย ตรงไปตรงมา เข้าใจอย่างไรก็เป็นแบบนั้น ไม่มีความซับซ้อน บางคนก็บอกว่ามันคือ pseudocode ที่ทำงานได้จริงๆ ผมเคยลองเขียน pseudocode ด้วย Python มันก็ดูสะอาดดี แต่ก็มีหลายคนไม่ชอบ เพราะไม่มีปีกกา {}
หรือ begin
end
แล้วไม่สบายใจ เหมือนชีวิตขาดอะไรไป โชคดีที่ผมไม่ใช่คนแรกที่สงสัย มีคนพยายามตอบหลายครั้ง ผมชอบคำอธิบายที่ Python Secret Weblog มากที่สุด เพราะมีตัวอย่างชัดเจน อย่างน้อยก็เห็นแล้วร้อง อ๋อ ไม่ต้องเสียเวลาจินตนาการ
ยกตัวอย่างแรกสุด เอาแบบง่ายๆ พื้นๆ
for (i=0; i) { do_something(mylist[i]); }
เวลาแปลงเป็น Python ตรงๆ จะได้เป็น
i = 0 while i < mylist_length: do_something(mylist[i]) i += 1
แต่จริงๆ แล้วถ้าจะเขียนแบบ Python ให้มากขึ้นซักนิด ก็ควรจะใช้ for
กับ range()
แทน
for i in range(mylist_length): do_something(mylist[i])
อย่างไรก็ตาม for
ไม่ควรใช้ index แต่ควรทำกับข้อมูลนั้นตรงๆ
for element in mylist: do_something(element)
จะเห็นว่าแบบสุดท้ายกระชับและเข้าใจง่ายที่สุด โอกาสผิดพลาดต่ำมาก ไม่ต้องกลัวว่า i
จะอยู่นอกสโคปของ mylist
ให้เปลืองสมอง ไม่ต้องใช้ตัวแปรหลายตัว
ลองมาดูตัวอย่างถัดไป ในภาษาทั่วไปเวลาเราต้องส่งค่ากลับมาหลายค่าก็ต้องส่งทางพารามิเตอร์
void foo(int *a,float *b) { *a = 3; *b = 5.5; }
เวลาใช้ก็แบบนี้
int alpha; int beta; foo(&alpha,&beta);
ถ้าเขียนแบบนี้เป๊ะๆ ใน Python จะได้แบบนี้
def foo(a,b): a[0] = 3 b[0] = 5.5 alpha = [0] beta = [0] foo(alpha,beta) alpha = alpha[0] beta = beta[0]
ที่ต้องทำแบบนี้เพราะว่า alpha
กับ beta
เป็นตัวแปรที่เก็บค่าล้วนๆ เวลาส่งเป็นพารามิเตอร์จะส่งไปเฉพาะค่า ไม่มีพอยเตอร์ซะด้วย ถ้าอยากจะทำตามนั้นจริงๆ ก็ต้องใช้ลิสต์เข้ามาช่วยจำลองพอยเตอร์ จากโค้ดข้างบนจะเห็นว่ามันเลวร้ายมาก ไม่มีความ Pythonic เอาซะเลย ลองมาดูแบบนี้บ้าง
def foo(): return 3,5.5 alpha,beta = foo()
เรียบง่าย ชัดเจน ไม่ได้หมายความว่าภาษาอื่นทำแบบนี้ไม่ได้ Ruby Perl PHP ทำแบบนี้ได้หมด ก็อย่างที่บอกตั้งแต่ต้น มันเป็นปรัชญา Python ไม่ได้สนับสนุนให้ทำแบบนี้ แต่มันทำได้ และนอกจากนี้ทำแล้วดีด้วย เขียน Python มากๆ แล้วจะรู้สึกว่าวิธีคิดเปลี่ยนไป กลายเป็นคิดแบบ Python คนพวกนี้จะกลายเป็น Pythonian ทุกภาษามีวิถีของตนเอง นี่คือวิถีของ Python
ลองมาดูตัวอย่างถัดไป ภาษา OOP อื่นๆ มักสนับสนุนให้ใช้ accessor เพื่อสร้าง setter getter สำหรับการอ่านเขียนค่าที่เก็บในอ๊อบเจ็ก แต่เรื่องพวกนี้ไม่จำเป็นใน Python
class A: def __init__(self,a,b): self.a = a self.b = b o = A('1',2) print o.a,o.b o.b = 3 print o.a,o.b
หลายคนสงสัยว่าแล้วอย่างนี้จะปลอดภัยรึเปล่า เรื่องความปลอดภัยและความถูกต้องเป็นเรื่องของผู้พัฒนา ถ้าเขียนโปรแกรมแล้วไม่รู้ว่าควรใส่ค่าอะไรลงในตัวแปรไหน ก็คงไม่ดีนัก พูดง่ายๆ ก็คือเขียนโปรแกรมต้องมีสติ ถ้าเขียนโปรแกรมแล้วต้องพึ่ง IDE เพื่อตรวจสอบทุกอย่าง ก็หมายความว่าโปรแกรมที่ได้จะถูกบังคับด้วยความสามารถของ IDE อะไรที่ IDE ทำไม่ได้ โปรแกรมเราก็ทำไม่ได้ กลายเป็นข้อจำกัดที่ไม่สามารถแก้ได้ ในขณะที่ Python อยากให้ผู้พัฒนารู้ว่ากำลังทำอะไร และทำให้ดีแม้ในส่วนเล็กน้อยด้วย ตามหลักการของ bottom-up เราสามารถนำชิ้นส่วนเล็กๆ มาประกอบเป็นชิ้นส่วนใหญ่ๆ ได้ ถ้าชิ้นส่วนเล็กๆ ไม่มีปัญหา การเอามาประกอบเป็นชิ้นที่ใหญ่ขึ้นก็ไม่ควรก่อปัญหา ถ้าชิ้นส่วนใหญ่ไม่มีปัญหาชิ้นส่วนที่ใหญ่กว่าก็ไม่ควรมีปัญหา ขอเพียงทำตามนี้ไม่ว่าโปรแกรมจะใหญ่แค่ไหนก็สามารถเขียนได้โดยที่ไม่ต้องพึ่ง IDE
ทิ้งท้ายเล็กน้อย ถ้าอยากใช้ getter setter ใน Python จริงๆ ก็สามารถทำได้ในแบบ Python
class A: def __init__(self,a,b): self.a = a self.b = b def get_a(self): return self.a def set_a(self,v): self.a = v a = property(get_a,set_a) def get_b(self): return self.b def set_b(self,v): self.b = v b = property(,get_b,set_b) a = A('1',2) a.a = '2' a.b = 3 print a.a,a.b
ตอนใช้เหมือนปกติ เปลี่ยนแค่ตอนเขียนเท่านั้น
- sugree's blog
- 1122 reads
เอาไปใส่ใ
Post new comment