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

บทเรียนจาก Zen of Python

เรียนรู้เกี่ยวกับ Zen of Python และค้นพบหลักการเขียนโค้ด Python ให้สะอาด งดงาม และอ่านง่าย
อัปเดตแล้ว 31 ส.ค. 2569  · 12 นาที อ่าน

สำรวจด้วย AI

ChatGPTClaudePerplexity

Zen of Python คืออะไร? 

Zen of Python คือชุดสุภาษิตสิบเก้าข้อที่ทำหน้าที่เป็นหลักการชี้นำสำหรับการออกแบบภาษา Python เดิมตั้งใจให้มียี่สิบข้อ แต่ Guido van Rossum ผู้สร้างภาษา Python ยังไม่ได้เพิ่มข้อสุดท้ายตามที่ Tim Peters ผู้ร่าง Zen of Python ตั้งใจไว้ โดย Guido เคยกล่าวติดตลกว่า สุภาษิตข้อที่ยี่สิบนั้นเป็น &ldquo>มุกในวงในของ Tim Peters ที่แปลกประหลาด”

แม้จะขาดสุภาษิตข้อที่ยี่สิบ แต่ Zen of Python ก็ได้รับการมาตรฐานเป็น PEP 20 ในปี 2004 เนื่องจากมีอิทธิพลอย่างมากต่อกระบวนการพัฒนาของโปรแกรมเมอร์ Python การยึดตาม Zen of Python ไม่ได้เป็นข้อบังคับ แต่ควรรู้และนึกถึงไว้เสมอ หากลืมบทเรียนเหล่านี้ สามารถเรียกความจำได้ง่ายๆ โดยรัน import this จากตัวแปลภาษา Python 

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

ในบทความนี้ จะพาไล่ดูแต่ละบทเรียนโดยละเอียดมากขึ้น 

#1 Beautiful is better than ugly 

หากเป็นโปรแกรมเมอร์อยู่แล้ว ย่อมมีทักษะสูงอยู่พอตัว การแก้ปัญหาด้วยโค้ดไม่ใช่เรื่องง่าย แต่ในฐานะ Pythonista ย่อมคาดหวังได้มากกว่านั้น โค้ดที่สวยงามดีกว่าโค้ดที่รุงรัง การเติบโตอย่างรวดเร็วของ Python ส่วนหนึ่งมาจากความเข้าถึงง่าย: เรียบง่าย อ่านง่าย และงดงาม ในฐานะผู้พัฒนา Python จึงมีความรับผิดชอบที่จะรักษามาตรฐานแบบ pythonic ด้วยการเขียนโค้ดให้สวยงาม 

แล้วโค้ดที่สวยคืออะไร? ก็ขึ้นกับมุมมอง—ความงามขึ้นอยู่กับผู้มองเป็นหลัก กฎง่ายๆ ที่ช่วยให้ไม่หลุดกรอบคือ เขียนโค้ดให้สะอาด อ่านง่าย และที่นักพัฒนาคนอื่นเข้าใจได้ไม่ยาก ตัวอย่างเช่น: 

"""
Initial code was created by Vishal Sharma
See:  https://towardsdatascience.com/the-zen-of-python-a-guide-to-pythons-design-principles-93f3f76d088a
"""
def collatz(num):
    if num % 2 == 0:
        return num // 2
    else:
        return 3 * num + 1

number = input("Enter a number: ")

while number != 1:
    number = collatz(int(number))
    print(number)

"""
Enter a number: 5
16
8
4
2
1
"""

โค้ดด้านบนทำงานได้ดี แต่ไม่จำเป็นต้องเรียกว่าสวย เพราะมีเงื่อนไข else ที่ไม่จำเป็นในฟังก์ชัน collatz ซึ่งสามารถตัดออกได้ดังนี้: 

def collatz(num):
  if num % 2 == 0:
      return num // 2
 
  return 3 * num + 1

ดังนั้นเมื่อมีตัวเลือกเป็นโค้ดที่ทำงานได้ทั้งคู่ ควรเลือกโค้ดที่ง่ายกว่า อ่านง่ายกว่า และเข้าใจได้ง่ายกว่า 

#2 Explicit is better than implicit

การบอกว่าสุภาษิตใดๆ ว่า “อธิบายตัวมันเองแล้ว” เป็นความผิดพลาดใหญ่หลวง—ถึงอย่างนั้นก็ยังมีคนทำอยู่ดี แก่นของ “ชัดเจนดีกว่าโดยนัย” คือ โค้ดที่บอกกล่าวอย่างตรงไปตรงมาดีกว่าโค้ดอ้อมค้อม ทำทุกวิถีทางเพื่อไม่ให้การทำงานของโค้ดถูกซ่อนอยู่หลังภาษาที่คลุมเครือ คนที่ไม่เคยรู้จักโปรแกรมของคุณมาก่อนก็ควรจะเข้าใจได้ว่ากำลังเกิดอะไรขึ้นในโค้ด 

#3 Simple is better than complex

คงอดหัวเราะไม่ได้ถ้าเพื่อนหยิบเครื่องฉีดน้ำแรงดันมาล้างจานหลังมื้อเย็น นอกจากจะเป็นวิธีที่ไม่เข้าท่า ยังมีโอกาสสูงที่จานจะเสียหาย ในทำนองเดียวกัน การใช้วิธีซับซ้อนมากๆ กับปัญหาโปรแกรมมิงที่เรียบง่ายนั้นไม่เป็นไปได้ในทางปฏิบัติ ไม่มีความจำเป็นต้องทำให้คำตอบซับซ้อนโดยไม่จำเป็น ต่อให้คิดว่าจะทำให้ดูฉลาดขึ้นก็ตาม สุดท้ายอาจทำให้เสียหายมากกว่าช่วยแก้ปัญหา ซึ่งไม่ใช่สิ่งที่ชื่นชอบในโลกของ Python 

ลองดูฟังก์ชันกลับสตริงนี้: 

def reverse_string(string):
    if len(string) == 1:
        return string
    else:
        return reverse_string(string[1:]) + string[0]


string = "kurtis"

print(reverse_string(string))

"""
sitruk
"""

โค้ดด้านบนแก้ปัญหาได้ก็จริง แต่ซับซ้อนโดยไม่จำเป็น หากเข้าใจ Python ดี จะรู้ว่าสามารถกลับสตริงด้วยการทำ indexing ได้ 

string = "kurtis"

# annonymous function solution
reverse_string = lambda x: x[::-1]

# function solution
def reverse(string):
    return string[::-1]

print(reverse_string(string))
print(reverse(string))

"""
sitruk
sitruk
"""

#4 Complex is better than complicated 

การล้างจานด้วยเครื่องฉีดน้ำแรงดันเป็นเรื่องไม่เข้าท่า: ใช้น้ำก๊อกธรรมดาน่าจะเหมาะกว่า แต่ถ้าต้องล้างรถ 4x4 Range Rover ล่ะ? สุภาษิตก่อนหน้าและข้อนี้เตือนเราว่า ปัญหาเดียวกันอาจแก้ได้ทั้งด้วยวิธีง่ายและวิธีซับซ้อน การล้าง Range Rover ไม่ใช่ปัญหาง่าย และการใช้เทคนิคเดียวกับการล้างจานอาจพอได้ แต่กลับยุ่งยากกว่าการใช้เครื่องฉีดน้ำแรงดัน ดังนั้นควรให้ความสำคัญกับความเรียบง่ายเหนือความซับซ้อน แต่เมื่อความเรียบง่ายใช้การไม่ได้ การเลือกความซับซ้อนย่อมดีกว่า—รู้ขอบเขตของความเรียบง่ายให้ดี 

#5 Flat is better than nested 

โปรแกรมเมอร์มักชอบจัดระเบียบสิ่งต่างๆ เป็นหมวด หมวดย่อย และหมวดย่อยของหมวดย่อย เพื่อแยกหน้าที่การทำงาน แม้จะฟังดูเป็นระเบียบ แต่การจัดแบบนั้นอาจทำให้สับสนมากกว่าจะช่วยจัดระเบียบ 

การใส่โค้ดทั้งหมดไว้ในมอดูลชั้นบนสุดก็ไม่ผิดอะไร: หมายความว่าไม่ต้องทำอะไรทำนอง from spam.foo.bar.john.doe import chicken เพื่อเข้าถึงฟังก์ชันบางอย่าง ยิ่งเพิ่มหมวดย่อยมาก โค้ดยิ่งซับซ้อนมาก ทำทุกทางเพื่อยึดโครงสร้างแบบแบนเมื่อเป็นไปได้

#6 Sparse is better than dense

โปรแกรมเมอร์มักถูกมองว่าเป็นคนฉลาดมากอยู่แล้ว จึงไม่จำเป็นต้องโอ้อวดสติปัญญาด้วยทริกพิสดาร หนึ่งในประโยคที่ได้ยินบ่อยคือ “ทำ [งานที่ซับซ้อนบางอย่าง] ในโค้ดบรรทัดเดียว” บางครั้งโค้ดบรรทัดเดียวก็มีเหตุผล แต่ควรหลีกเลี่ยงการแลกความอ่านง่ายเพื่อยัดทุกอย่างลงในบรรทัดเดียว 

ลองดูโค้ดชุดนี้เป็นตัวอย่าง: 

"""
Code source Al Sweigart
See: https://inventwithpython.com/blog/author/al-sweigart.html0
"""
print('\n'.join("%i bytes = %i bits which has %i possible values." % (j, j*8, 256**j-1) for j in (1 << i for i in range(8))))
"""
1 bytes = 8 bits which has 255 possible values.
2 bytes = 16 bits which has 65535 possible values.
4 bytes = 32 bits which has 4294967295 possible values.
8 bytes = 64 bits which has 18446744073709551615 possible values.
16 bytes = 128 bits which has 340282366920938463463374607431768211455 possible values.
32 bytes = 256 bits which has 115792089237316195423570985008687907853269984665640564039457584007913129639935 possible values.
64 bytes = 512 bits which has 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095 possible values.
128 bytes = 1024 bits which has 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215 possible values.
"""

โค้ดนี้ทำงานได้แน่นอน แต่ชวนปวดหัวสุดๆ ในการทำความเข้าใจ ทั้งอัดแน่นและอ่านยาก 

มาดูว่าเมื่อเขียนให้โปร่งขึ้นจะเป็นอย่างไร: 

# Sparse example
bytes_and_bits = {j: j*8 for j in (1 << i for i in range(8))}

for bytes, bits in bytes_and_bits.items():
    print(f"{bytes} bytes = {bits} which has {256**bytes-1} possible values")

"""
1 bytes = 8 which has 255 possible values
2 bytes = 16 which has 65535 possible values
4 bytes = 32 which has 4294967295 possible values
8 bytes = 64 which has 18446744073709551615 possible values
16 bytes = 128 which has 340282366920938463463374607431768211455 possible values
32 bytes = 256 which has 115792089237316195423570985008687907853269984665640564039457584007913129639935 possible values
64 bytes = 512 which has 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095 possible values
128 bytes = 1024 which has 179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137215 possible values
"""

โค้ดด้านบนอ่านง่ายขึ้นมาก และทำสิ่งเดียวกันกับเวอร์ชันบรรทัดเดียวทุกประการ

#7 Readability counts

ถ้ายังเดาไม่ออก—ความอ่านง่ายคือหัวใจของ Python งานของคุณคือเขียนโค้ดครั้งเดียว แต่มีโอกาสสูงที่มันจะถูกอ่านซ้ำหลายครั้ง ดังนั้นการตัดสระทิ้งจากชื่อตัวแปรและชื่อฟังก์ชันไม่ใช่ความคิดที่ดี เมื่อมีทางเลือกตั้งชื่อฟังก์ชันว่า create_lst หรือ create_list ให้เลือกอย่างหลัง 

#8 Special cases aren’t special enough to break the rules

Python [และโปรแกรมมิงโดยทั่วไป] เต็มไปด้วยแนวปฏิบัติที่ดีต่างๆ ให้ยึดถือ การทำตามแนวปฏิบัติที่ดีย่อมดีกว่าทำตามใจตัวเอง เพราะมักนำไปสู่โค้ดที่ไม่สม่ำเสมอและอ่านยาก 

#9 Although practicality beats purity

บทเรียนที่เก้าต่อยอดจากบทเรียนที่แปด ใช่—การทำตามแนวปฏิบัติที่ดีเป็นเรื่องดีกว่า แต่การพยายามทำตามกฎอย่างเคร่งครัดก็อาจทำให้โค้ดอ่านยากได้เช่นกัน ดังนั้นกฎแต่ละข้ออาจมีข้อยกเว้น หากวิธีแก้ปัญหาของคุณใช้การได้จริง อ่านง่าย และเข้าใจง่ายกว่า ก็ควรเบี่ยงจากแนวปฏิบัติที่ยึดกันอยู่ได้ 

#10 Errors should never pass silently 

ข้อผิดพลาดแบบเงียบ คือกรณีที่โปรแกรมคืนรหัสผิดพลาดหรือ None แทนการยกข้อยกเว้น ควรปล่อยให้โปรแกรมล่มดีกว่าปิดเสียงข้อผิดพลาดแล้วปล่อยให้ทำงานต่อไป ระยะยาวการปิดเสียงข้อผิดพลาดอาจก่อบั๊กที่กำจัดได้ยากกว่าเดิมมาก 

#11 Unless explicitly silenced

บทเรียนที่สิบเอ็ดต่อยอดจากบทเรียนที่สิบ มีบางกรณีที่อาจต้องการเพิกเฉยข้อผิดพลาดที่เกิดจากโปรแกรม ในกรณีเช่นนั้น แนวปฏิบัติที่ดีคือปิดเสียงข้อผิดพลาดนั้นอย่างชัดแจ้งในโค้ด 

#12 In the face of ambiguity, refuse the temptation to guess

คอมพิวเตอร์ทำเฉพาะสิ่งที่สั่งให้ทำ: หากโค้ดทำงานไม่เป็นอย่างที่หวัง นั่นเพราะมันทำสิ่งที่คุณสั่งไว้อย่างนั้น การพยายามแก้พฤติกรรมโดยลองวิธีต่างๆ แบบเดาสุ่มจนกว่าจะเวิร์กเป็นกลยุทธ์ที่ไม่ดี—อาจกลบปัญหาแทนที่จะแก้มัน หักห้ามใจไว้ แล้วคิดตรรกะของปัญหาให้รอบคอบ ใช้วิจารณญาณเพื่อหาวิธีที่เหมาะสม 

#13 There should be one - and preferably only one - obvious way to do it 

สโลแกนของภาษา Perl คือ “มีหลายวิธีในการทำสิ่งเดียว!” ตัวเลือกมากเกินไปมักนำไปสู่ภาวะล้นตัวเลือก สถานการณ์คล้ายกันเกิดขึ้นเมื่อมีหลายวิธีเขียนโค้ดให้ได้ผลลัพธ์เดียวกัน แม้จะยืดหยุ่นขึ้นในการเขียน แต่ตอนอ่านต้องเรียนรู้ทุกวิธีที่โค้ดอาจถูกเขียนมา งานส่วนเกินในการเรียนรู้ทุกสถานการณ์นั้นไม่จำเป็น 

#14 Although that way may not be obvious at first unless you're Dutch

สุภาษิตข้อนี้สะท้อนอารมณ์ขันของ Tim Peters: Guido van Rossum ผู้สร้างภาษา Python และ Benevolent Dictator For Life (BDFL) ของ Python เป็นชาวดัตช์ เป็นมุกเตือนใจว่า การเข้าใจและจำกฎของภาษา Python ไม่ใช่เรื่องง่ายสำหรับใครๆ ยกเว้นผู้สร้างเอง 

#15 Now is better than never

สุภาษิตนี้สื่อว่า โค้ดที่ติดลูปไม่มีที่สิ้นสุดหรือแขวนค้างอยู่ แย่กว่าโค้ดที่ไม่เป็นเช่นนั้น 

#16 Although never is often better than *right* now

ต่อเนื่องจากบทเรียนที่สิบหก: รอให้โปรแกรมรันจบย่อมดีกว่าหยุดมันกลางคันแล้วได้ผลลัพธ์ที่ผิด 

#17 If the implementation is hard to explain, it’s a bad idea

แค่ตัวเองเข้าใจการอิมพลีเมนต์ของตัวเองไม่เพียงพอ—คำว่า “รู้น่าว่ากำลังจะสื่ออะไร” ใช้การไม่ได้ การเขียนโปรแกรมคือกิจกรรมแบบทีม หากอธิบายอิมพลีเมนต์ให้เพื่อนไม่ได้ ก็มีแนวโน้มสูงว่าทำให้คำตอบซับซ้อนเกินไป 

#18 If the implementation is easy to explain, it may be a good idea

อย่างไรก็ตาม โค้ดที่อธิบายง่ายไม่ได้แปลว่าเป็นโค้ดที่ดีเสมอไป—มันแค่ทำให้อธิบายได้ง่าย ยังอาจเป็นโค้ดที่ไม่ดีอยู่ แต่การที่อธิบายง่ายก็แปลว่ามาได้ถูกทางแล้ว 

#19 Namespaces are one honking great idea - let’s do more of those!

เนมสเปซคือนามธรรมใน Python ที่ใช้จัดระเบียบชื่อที่ผูกกับออบเจ็กต์ในโปรแกรม เมื่อมีเนมสเปซและสโคปเฉพาะ Python จะระบุได้ว่าหมายถึงออบเจ็กต์ใดเมื่อเรียกด้วยชื่อเชิงสัญลักษณ์ สุภาษิตข้อนี้บอกว่า วิธีที่ Python จัดระเบียบชื่อเชิงสัญลักษณ์เบื้องหลังนั้นยอดเยี่ยมมาก 

สรุป 

บทความนี้ได้นำเสนอการตีความ Zen of Python ของเรา ซึ่งเป็นแนวทางที่สร้างขึ้นเพื่อกระตุ้นให้โปรแกรมเมอร์ Python เขียนโค้ดให้สะอาดและอ่านง่าย บางคนมอง Zen of Python เป็นแม่แบบสูงสุดของการเขียนโค้ดอย่างลื่นไหล ขณะที่บางคนก็ไม่ได้จริงจังถึงเพียงนั้น แนะนำให้ลองนำหลักการเหล่านี้ไปใช้กับโค้ดของตัวเองเพื่อเห็นผลด้วยตนเอง หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการเขียนโค้ดให้มีประสิทธิภาพ ลองดูคอร์ส Writing Efficient Python Code ของ DataCamp  

หัวข้อ
Python
วิทยาการข้อมูล

คอร์ส Python บน DataCamp 

Courses

Python เบื้องต้น

4 ชม.
7M
เชี่ยวชาญพื้นฐานการวิเคราะห์ข้อมูลด้วย Python ในเวลาเพียงสี่ชั่วโมง คอร์สออนไลน์นี้จะแนะนำอินเทอร์เฟซ Python และสำรวจแพ็กเกจยอดนิยม
ดูรายละเอียดRight Arrow
เริ่มหลักสูตร

Courses

Python เบื้องต้นสำหรับ Data Science

4 ชม.
502.2K
ดำดิ่งสู่ data science ด้วย Python และเรียนรู้วิธีวิเคราะห์และแสดงผลข้อมูลของคุณอย่างมีประสิทธิภาพ ไม่จำเป็นต้องมีประสบการณ์หรือทักษะด้านการเขียนโค้ด
ดูเพิ่มเติมRight Arrow