มาตรฐานการเขียนโปรแกรม Python

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

โดยมาตรฐานเหล่านี้จะถูกตรวจสอบโดยระบบตรวจสอบโค้ด (หรือที่เรียกว่า Linter) ซึ่งในที่นี้ก็คือ PyLint

สำหรับน้องๆ ที่ต้องการอ่านรายการ PEP8 ทั้งหมด (ซึ่งแนะนำมากๆ ว่าให้อ่าน) ก็สามารถเข้าไปที่ https://www.python.org/dev/peps/pep-0008/open in new window


Missing DocString

Docstring คือ comment เพื่อบอกว่าฟังชั่น หรือ โปรแกรมนั้นๆ ทำงานเพื่ออะไร โดยทุก function ละหัวไฟล์ (บรรทัดที่ 1) จะต้องมี docstring กำกับ

เช่น

"""
This program will print out the "Happy Kumamon" to the world
"""

def happyKumamon():
  """This function will print out the text"""
  print("Hello Kumamon")
happyKumamon()

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


Missing new line

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

StackOverflow Reference : https://stackoverflow.com/questions/729692/why-should-text-files-end-with-a-newlineopen in new window

โดยที่พวก Text Editor ส่วนใหญ่ จะมีการทำให้อยู่แล้ว

"""This program will print out the "Happy Kumamon" to the world"""
def happy():
  """This function will print out the text"""
  print("Hello Kumamon")
happy()
# and leave this line blank

Invalid Data Type

เป็นการบอกว่าไม่สามารถทำการแปลงประเภทตัวแปร (Casting) ได้

เช่น

int(input())

ถ้าหากรับค่า int มันจะแปลงจาก string เป็น int ปกติ ถ้าหากรับค่า string มันจะแปลงไม่ได้ เพราะ string เป็นตัวอักษร เปลี่ยนค่าเป็นตัวเลขไม่ได้นะจ๊ะ


Invalid Syntax

การใช้ฟังชั่นที่ใช้ชื่อผิด ใช้ผิดวิธี โมดูลขาด argument หรือ ไม่ได้เรียกโมดูลที่ต้องการใช้มาก่อน

TIP

ก่อนส่ง น้องๆ ควรที่จะทดสอบการทำงานก่อนหนึ่งครั้งว่าทำงานเหมือนกับที่ต้องการหรือไม่

การแจ้ง Invalid Syntax นั้นมักเกิดขึ้นตั้งแต่มีการ Compile โค้ด ดังนั้น Python Compiler ก็จะหยุดการรันโค้ดทันที

เช่น

import math
var_x = pi()

ซื่ง pi() ไม่ใช่ฟังชั่นใน python หลัก แต่เป็นส่วนหนึ่งของ library ชื่อ math

ดังนั้น หากจะแก้ให้ถูก จึงต้องใช้

import math
var_x = math.pi()

Unused Variables

เป็นการประกาศตัวแปร แล้วน้องไม่เคยใช้มันเลย มันอาจจะไม้เป็นไรสำหรับการรัน เพราะก็สามารถรันได้อย่างปกติ แต่มันเปลืองพื้นที่ RAM (เพื่อจองพื้นที่สำหรับ variable นี้) ทำให้ Pylint ด่า

ซึ่ง การประกาศแล้วไม่ได้ใช้ วิธีแก้ก็คือ ไม่ต้องไปประกาศครับ ง่ายเนอะ

เช่น

kumamon = "Happy"
var_x = 12
var_y = 21
print(var_x + var_y)

ซึ่งตัวแปร kumamon ไม่ได้ถูกใช้ในบรรทัดอื่น (นอกจากการประกาศค่า) เป็นการสี้นเปลืองทรัพยากร

Variable Error

การตั้งชื่อ Variable แต่ไปชื่อเดียวกันกับชื่อ Module ก็จะทำให้มันงง ว่าต้องการจะเรียก Module ที่ชื่อ math หรือเรียกตัวแปรที่ชื่อว่า math

เช่น

import math

math = "Kumamon" # ตั้งชื่อตัวแปรเหมือนชื่อ Module

print(math.fabs(20 - 99))

หรือ

aaa = 12
bbb = 55

print(aaa + bbb)

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

ดังนั้นพี่มงเลยมี Checklist ที่มันน่าจะด่านะครับ 😃

TypeMeaningExample
1Short Variableชื่อตัวแปรสั้นเกินไปเช่น
a
2Long Variableชื่อตัวแปรยากเกินเหตุเช่น
uvuvwevwevwe_onyetenyevwe_ugwemubwen_ossas
3Variable Name is the same as functionชื่อตัวแปรเหมือนชื่อฟังชั่นเช่น
if
4Vague Variable Nameตั้งชื่อตัวแปรอย่างง่ายๆเช่น
aaa
5Capitalized Variableตัวแปรที่มีการตั้งเป็นตัวใหญ่ด้านหน้า (การเขียนแบบนี้เอาไว้ใช้สำหรับการเขียนชื่อ class)เช่น
Num_1
6Camel Cased Variableตัวแปรที่ใช้การตั้งค่าเป็นตัวใหญ่แบ่งคำ (ซ้ำกับวิธีการตั้งชื่อ function)เช่น
distanceOverTime
7All Capitalized Variable (inside function)ตัวแปรที่เป็นตัวใหญ่หมดเมื่อประกาศใน Local Variableเช่น
DISTANCE
8Weird Variable Nameตัวแปรไม่บ่งบอกถึงการใช้งานเช่น
num_1 สำหรับการเก็บค่า distance

ดังนั้น น้องๆจะต้องระวังในการตั้งชื่อนะครับ

และระบบก็จะไม่แจ้งนะครับ ว่าตัวแปรไหนผิดด้วยสาเหตุใด น้องๆก็ต้องไปดูแล้วทำการแก้ไขด้วยตนเองนะครับ


Bad White Space

การที่มี white space ในจุดที่มันไม่จำเป็น เป็นการทำให้โค้ดของน้องๆสกปรก ไม่ดีเลย

เช่น (พี่จะแทน space ด้วย · นะครับ จะได้เห็นกันง่ายๆ)

print("Hello World")·
var_x,var_y = 12,21
print(var_x,var_y)

ในนี้ Pylint จะด่าในบรรทัด print("Hello World")* เพระตัว PyLint เห็น Whitespace ในตัวสุดท้ายนั่นเอง

อีกเหตุการณ์หนึ่งของการเกิด Whitespace ก็คือกด space หรือไม่กด ตามที่ standard เขียนไว้ ตัวอย่างเช่น

var_x,var_y = 12,21
print(var_x,var_y)

ตัว PyLint จะด่า print(var_x,var_y) เพราะ การใช้ , ควรจะเหมือนเขียนภาษาอังกฤษนะครับ ต้องมี space หลัง , อย่างเช่น

var_x,·var_y = 12, 21
print(var_x, var_y)

Too much Local Variable

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

เช่น

def main():
    var_a = 12
    var_b = 13
    var_c = 14
    var_d = 15
    var_e = 15
    var_f = 16
    var_g = 17
    var_h = 18
    var_i = 19
    var_j = 20
    var_k = 21
    var_l = 22
    var_m = 23

main()

การเก็บข้อมูลแบบนี้ดูเหมือนจะเปลืองทรัพยากรการเก็บข้อมูลมากเลย มันเลยด่านะครับ

น้องๆควรที่จะใช้ List หรือ Dict แทน เพื่อให้เก็บข้อมูลให้เรียกใช้งานได้มากกว่านี้ครับ

Too much Global Variable

เหมือนกับข้อที่แล้วเลยจ้า มันเปลืองพื้นที่ (การเก็บตัวแปรเป็นแบบ Global เปลืองทรัพยากรมากกว่า local อีกนะครับ จะบอกให้)

เช่น

VAR_A = 12
VAR_B = 13
VAR_C = 14
VAR_D = 15
VAR_E = 15

เพราะการเก็บตัวแปรแบบ Global เหมาะกับตัวแปรที่ถูกเปลี่ยนแปลงบ่อย หรือตัวแปรที่ทุก Function ควรรู้ครับ

Line is too long

เป็นการบอกว่าโปรแกรมในแถวใดแถวหนึ่งยาวมาก
โดยปกติแล้ว โปรแกรมก็ไม่ควรที่จะยาวเกิน 100 ตัวอักษร อยู่แล้ว เพราะด้วยเหตุผลการอ่านไม่ออกล้วนๆครับ

เช่น

print("This is a very long string, and they are more than 100 character long. They just keep going and going and going and going and going and going and going and going and going and going")

Too many condition branch

เมื่อน้องต้องการทำ statement ซ้อนกันมาก (Chained IF หรือ Chain Loop) ก็จะโดนด่าแบบนี้ครับ

เช่น

    var_x = int(input())
    if var_x == 1:
        print("Var_x is equal to", var_x)
    else:
        if var_x == 2:
            print("Var_x is equal to", var_x)
        else:
            if var_x == 3:
                print("Var_x is equal to", var_x)
            else:
                if var_x == 4:
                    print("Var_x is equal to", var_x)
                else:
                    if var_x == 5:
                        print("Var_x is equal to", var_x)
                    else:
                        if var_x == 6:
                            print("Var_x is equal to", var_x)
                        else:
                            if var_x == 7:
                                print("Var_x is equal to", var_x)
                            else:
                                if var_x == 8:
                                    print("Var_x is equal to", var_x)
                                else:
                                    if var_x == 9:
                                        print("Var_x is equal to", var_x)
                                    else:
                                        if var_x == 10:
                                            print("Var_x is equal to", var_x)
                                        else:
                                            if var_x == 11:
                                                print("Var_x is equal to", var_x)
                                            else:
                                                if var_x == 12:
                                                    print("Var_x is equal to", var_x)
                                                else:
                                                    if var_x == 13:
                                                        print("Var_x is equal to", var_x)
                                                    else:
                                                        if var_x == 14:
                                                            print("Var_x is equal to", var_x)
                                                        else:
                                                            if var_x == 15:
                                                                print("Var_x is equal to", var_x)

หากว่าน้องอยากจะใช้เยอะจริงๆ พี่ก็แนะนำว่าให้น้องใช้หลักการ Function หรือ Recursion แทนนะครับ จะประหยัดบรรทัดโค้ดลงไปได้เยอะเลย

Mixing Tabs and Space

การใช้ Python น้องๆก็รู้ๆอยู่นะครับ ว่าจะไม่มีการใช้ {} ในการให้โปรแกรมรู้ว่าอยู่ในระดับขั้นตอนไหน
ซึ่งการ indent ที่ดี ก็เป็นสี่งจำเป็น เพื่อให้ Python เข้าใจน้องๆนะครับ
การ Indent จะใช้เท่ากับการกด space 4 ครั้งครับ ไม่ใช่ Tab
เช่น (พี่จะแทนที่ space ด้วย · และ tab ด้วย ⇥ นะครับ)

อันนี้เป็นตัวอย่างที่ถูกต้องนะครับ

def main():
····print("Hello world")

main()

อันนี้ผิด

def main():print("This is a very long string, and they are more than 100 character long. They just keep going and going and going and going and going and going and going and going and going and going")

main()

ซึ่งเวลาน้องเห็นบน Text Editor มันจะเหมือนกันมากๆเลย แทบจะดูไม่ออก ดังนั้น น้องต้องระวังนะครับ

พี่ก็ขอแนะนำให้น้องเปิด Invisible Character หรือน้องก็สามารถเอา mouse ไปลากได้ โดยหากว่าเป็น space น้องๆก็จะเห็นเป็นจุด (°) แต่หากว่าเป็น TAB ก็จะเห็นเป็นลูกศร (⇥) ครับ


Too many arguments in function

เป็นคำเตือนที่เกิดขึ้นจากว่า น้องทำการเขียน Function และรับ Parameter มากเกิดไปครับ

ตัวอย่างเช่น

def main():
    var_a = int(input())
    var_b = int(input())
    var_c = int(input())
    var_d = int(input())
    var_e = int(input())
    var_f = int(input())
    var_g = int(input())
    var_h = int(input())
    return calculate(var_a, var_b, var_c, var_d, var_e, var_f, var_g, var_h)

def calculate(var_a, var_b, var_c, var_d, var_e, var_f, var_g, var_h):
    print("The answer is", var_a + var_b + var_c + var_d + var_e + var_f + var_g + var_h)

main()

Conflicted variable Name

โดยจะเกิดขื้นเมื่อต้องการให้ตัวแปรนึงไปเป็นตัวนับ (ซึ่งตัวนับจะถูกลบล้างไป หากมีการใช้งาน) ดังนั้น ตัว PyLint จึงด่าครับ

x = 12
for x in range(1, 10):
    print(x)

หากต้องการแก้ไข ให้เปลี่ยนชื่อตัวแปรไม่ให้ซ้อนทับกันครับ

x = 12
for i in range(1, 10):
    print(i)

Incorrect line indentation

โดยอันนี้จะเกิดขื้นเมื่อน้องอยากให้ตัวโปรแกรมเหลือบรรทัดน้อยๆ หรือเกิดจากน้องลืมกด ENTER เพื่อเปลี่ยนบรรทัด เช่น
แต่โดยปกติแล้ว โปรแกรมจะไม่รันเลย เนื่องจากว่าไม่เข้าใจว่าต้องการทำอะไร
แต่สำหรับบางเหตุการนั้น ได้เฉยเลย พี่เลยเขียนไว้ก่อนนะครับ ว่าให้ศึกษาก่อนที่จะ shorthand coding นะจ๊ะ

# Normally what it should be
if (x > 12):
    print(x)

# This is incorrect way to shorthand if functions
if (x > 12): print(x)

# This is correct way to shorthand if function
print(x) if (x > 12)

Pylint จะด่า เพราะน้องส่งตัวแปรให้กับฟังชั่น calculate มากเกินไป 😦

พี่มงเจอแค่ปัญหาพวกนี้นะครับ ถ้าอันไหนพี่ยังไม่ได้อธิบาย ฝากเขียนไว้ใน Issues ให้พี่ด้วยจ้า