Thursday, March 4, 2010

Python Programming

More on Function
ประพัฒน์ สุริยผล

ครั้งนี้ เราจะทำให้โปรแกรมที่เราเขียนขึ้นเอง อ่านง่าย กะทัดรัด และแก้ไขได้ง่ายขึ้นไปอีก

เมื่อครั้งก่อนเราใช้ฟังก์ชัน เพื่อช่วยแบ่ง code ที่อยู่ในกลุ่มเดียวกันออกไปอยู่เป็นฟังก์ชัน ทำให้เรามองเห็น structure และ flow การทำงานของโปรแกรมได้ดีขึ้น ถ้าหากเราไม่แบ่งฟังก์ชัน เงื่อนไขต่างๆ ของ if คงจะไม่ชัดเจนและอยู่ใกล้กันอย่างที่เรามีอยู่

ครั้งนี้ เราจะใช้ฟังก์ชันเข้ามาช่วยเราในอีกกรณีหนึ่ง ซึ่งมีความสำคัญมาก ควรที่จะเรียนรู้อย่างยิ่ง นั่นคือการใช้ฟังก์ชันเพื่อลด code redundancy หรือ code duplication ทุกครั้งที่เราเขียน code ที่ดูเหมือนจะซ้ำๆ กัน เมื่อเราต้องการแก้ไขโปรแกรม สิ่งที่มักจะเกิดขึ้นก็คือ เราจะได้เข้าไปแก้ไขที่ code เหล่านั้นทุกที่ บางครั้งการลืมแก้ไขในบางที่ ก็จะทำให้โปรแกรมทำงานผิดพลาด

ลองดูที่ code ข้างล่างนี้

def calculateRectangleArea():
____print "Program to calculate Area of Rectangle"
____base = raw_input("Please enter base -> ")
____height = raw_input("Please enter height -> ")
____base_int = int(base)
____height_int = int(height)
____print "Rectangle area of base", base, "and height", height,\
__________"is", base_int*height_int

def calculateTriangleArea():
____print "Program to calculate Area of Triangle"
____base = raw_input("Please enter base -> ")
____height = raw_input("Please enter height -> ")
____base_int = int(base)
____height_int = int(height)
____print "Triangle area of base", base, "and height", height, "is",\
__________base_int*height_int*0.5

def calculateCircleArea():
____print "Program to calculate Area of Circle"
____radious = raw_input("Please enter radious -> ")
____radious_int = int(radious)
____print "Circle area of radious", radious, "is", 3.14159*radious_int*radious_i

เราจะเห็น pattern ที่ซ้ำๆ กันอยู่ในฟังก์ชัน ประเด็นสำคัญคือเราจะสร้างฟังก์ชันใหม่อย่างไรให้เหมาะสม จุดนี้เป็นจุดสำคัญที่สามารถเรียนรู้ได้จากประสบการณ์และดู code ที่คนอื่นเขียน

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

def calculateRectangleArea():
____print "Program to calculate Area of Rectangle"
____base = getUserInput("Please enter base -> ")
____height = getUserInput("Please enter height -> ")
____print "Rectangle area of base", base, "and height", height, "is", base*height

อันที่จริง สิ่งนี้เป็น code ที่เราต้องการเขียนตั้งแต่ต้น อ่านตรงไปตรงมา ไม่ต้องกังวลว่าค่าที่คืนมาต้องแปลงให้เป็น integer สิ่งที่เราต้องทำตอนนี้ก็คือ ฟังก์ชัน getUserInput ยังไม่มี ภาษา python ไม่มีฟังก์ชันนี้ และเป็นหน้าที่ของเราที่ต้องเขียนฟังก์ชันนี้ขึ้นมาใช้เอง

เราเริ่มต้นด้วยการ นิยามฟังก์ชัน

def getUserInput(text_to_display):

จะเห็นว่านิยามครั้งนี้ต่างจากครั้งแรกที่ในวงเล็บเราใส่ชื่อตัวแปรเอาไว้ ในที่นี้คือ text_to_display เราเรียกตัวแปรนี้ว่า พารามิเตอร์ (parameter) เพราะถ้าเราสังเกตคำสั่งที่ใช้เรียกฟังก์ชันนี้ จะมีการส่งค่าประโยคที่ต้องการถามผู้ใช้ไปให้ฟังก์ชัน เพราะฉะนั้น เราต้องเตรียมตัวแปรพารามิเตอร์เอาไว้เพื่อรองรับสิ่งที่ส่งมา

เมื่อฟังก์ชันถูกเรียกใช้ ตัวแปร text_to_display ก็จะมีค่าตามที่ถูกใช้ส่งมา สิ่งที่ต้องทำก็คือนำตัวแปรนี้ไปใช้ต่อ ดังด้านล่าง

def getUserInput(text_to_display):
____input = raw_input(text_to_display)
____return int(input)

สิ่งที่ฟังก์ชันนี้ทำ คือนำ text_to_display ไปใช้ต่อในคำสั่ง raw_input เพื่อรับค่าจากผู้ใช้ เสร็จแล้วจึงคืนค่าที่แปลงเป็น integer กลับไป ด้วยคำสั่ง return ถ้าหากฟังก์ชันไม่ต้องคืนค่าใดๆ เราก็ไม่ต้องใช้คำสั่ง return (เหมือนที่เราเรียกใช้ฟังก์ชัน calculateRectangleArea() หรือฟังก์ชันอื่นๆ ก่อนหน้านี้) ค่าที่คืนกลับไปจะเป็นตัวเลขเรียบร้อย ไม่จำเป็นต้องแปลงค่าต่อไปอีก

แบบฝึกหัด

ให้แปลงโปรแกรมที่เขียนขึ้น ให้เรียกใช้ getUserInput แล้วดูว่า โปรแกรมกะทัดรัดขึ้นหรือไม่ จำนวนบรรทัดลดลงไหม อ่านง่ายขึ้นหรือไม่

Good and Not So Good Programs

โปรแกรมที่ดีไม่จำเป็นต้องเป็นโปรแกรมที่สั้นที่สุด (จำนวนบรรทัดน้อยที่สุดเสมอไป) แต่ส่วนใหญ่โปรแกรมที่ดีมักจะสั้นกว่าโปรแกรมที่ไม่ค่อยดี เพราะโปรแกรมที่ดีจะไม่มี code ที่ซ้ำซ้อน ส่วนที่ซ้ำซ้อนจะถูกแยกออกมาเป็นฟังก์ชัน แต่สิ่งนี้ก็ไม่ใช่กฎตายตัว code ที่แยกฟังก์ชันยิบย่อยเกินไป หรือแยกฟังก์ชันในตำแหน่งที่ไม่ควรจะแยก จะทำให้โปรแกรมนั้นกลายเป็นโปรแกรมที่ไม่ดีได้

ลักษณะของโปรแกรมที่ดีคือ
1. ทำงานได้ถูกต้อง (สำคัญที่สุด ถูกไหม)
2. อ่านเข้าใจง่าย (ชื่อตัวแปรชัดเจน ชื่อฟังก์ชันชัดเจน การทำงานของโปรแกรมสามารถทำความเข้าใจได้ง่าย)
3. สามารถปรับเปลี่ยนเพิ่มเติมหรือแก้ไขได้ง่าย หากต้องการเพิ่มคุณสมบัติต่างๆ เข้าไป สามารถทำได้ โดยแทบจะไม่ต้องแก้ไขส่วนที่เขียนไว้อยู่แล้ว ที่เป็นเช่นนี้ เพราะถ้าหากเราต้องเข้าไปแก้ไขส่วนที่เขียนไว้อยู่แล้ว จะมีโอกาสสูงที่เราจะทำให้โปรแกรมทำงานผิดพลาดได้ โดยเฉพาะโปรแกรมที่เราต้องการแก้ไขเป็นโปรแกรมขนาดใหญ่หรือไม่ได้เขียนด้วย ตัวเราเอง
4. สั้น และกะทัดรัดที่สุด เท่าที่ไม่รบกวนกฎข้อที่ 1 และ 2

แบบฝึกหัด

ลองดูโปรแกรมแบบต่างๆ 6 แบบดังด้านล่าง แล้วให้คะแนนตั้งแต่ 1-3 (1 ต่ำสุด 3 สูงสุด) พร้อมเหตุผลประกอบ ในแต่ละหัวข้อดังต่อไปนี้

1. โปรแกรมทำงานถูกต้อง ตามที่ต้องการไหม (คะแนน 1-3)
2. โปรแกรมอ่านเข้าใจง่ายไหม (คะแนน 1-3)
3. ถ้าต้องการเพิ่มการคำนวณพื้นที่รูปร่างอื่นๆ เข้าไปอีก ทำได้ง่ายไหม (คะแนน 1-3)
4. ความสั้นและกะทัดรัด (คะแนน 1-3)

แบบที่ 1

def calculateRectangleArea():
____print "Program to calculate Area of Rectangle"
____base = getUserInput("Please enter base -> ")
____height = getUserInput("Please enter height -> ")
____print "Rectangle area of base", base, "and height", height, "is", base*height

def calculateTriangleArea():
____print "Program to calculate Area of Triangle\nTriangle area = 0.5*base*height"
____base = getUserInput("Please enter base -> ")
____height =getUserInput("Please enter height -> ")
____print "Triangle area of base", base, "and height", height, "is", 0.5*base*height

def calculateCircleArea():
____print "Program to calculate Area of Circle\nCircle area = 3.14159 * radius^2"
____radius = getUserInput("Please enter radius -> ")
____print "Circle area with radius", radius, "is", 3.14159 *radius**2

def calculateTrapezoidsArea():
____print "Program to calculate Area of Trapezoids"
____# = 0.5 * (parallelbase1+parallelbase2)* height
____parallelbase1 = getUserInput("Please enter parallel base1 -> ")
____parallelbase2 = getUserInput("Please enter parallel base2 -> ")
____height = getUserInput("Please enter height -> ")
____print "Trapozoids area of parallel base1", parallelbase1, "parallel base2",\
__________parallelbase2, "and height", height, "is",\
__________0.5*(parallelbase1 + parallelbase2)*height

def getUserInput(text_to_display):
____input = raw_input(text_to_display)
____return int(input)

choice = raw_input("Which type of area you would like to calculate (R/T/C/Z)? -> ")
if choice == "R" or choice == "r":
____calculateRectangleArea()
elif choice == "T" or choice == "t":
____calculateTriangleArea()
elif choice == "C" or choice == "c":
____calculateCircleArea()
elif choice == "Z" or choice == "z":
____calculateTrapezoidsArea()
else:
____print "Please type R,T,C or Z to choose the type of area to calculate"

แบบที่ 2

def calculateArea(Area):
____print "Program to calculate Area of", Area
____base = getUserInput("Please enter base -> ")
____height = getUserInput("Please enter height -> ")
____if Area == "Rectangle":
________print "Rectangle area of base", base, "and height", height, "is", base*height
____elif Area == "Triangle":
________print "Triangle area of base", base, "and height", height, "is", 0.5*base*height

def calculateCircleAndTrapezoids(Value):
____if Value == "Circle":
________radius = getUserInput("Please enter radius -> ")
________result = 3.14159*(radius**2)
________print "Circle area of radius", radius, "is", result
____elif Value == "Trapezoids":
________height = getUserInput("Please enter height -> ")
________parallel_base_top = getUserInput("Please enter parallel_base_top -> ")
________parallel_base_bottom = getUserInput("Please enter parallel_base_bottom -> ")
________print "Trapezoids area of parallel base top and bottom", parallel_base_top, \
______________"and", parallel_base_bottom, "and height", height, "is", \
______________1.0/2.0*(parallel_base_top + parallel_base_bottom)*height

def getUserInput(text_to_display):
____input = raw_input(text_to_display)
____return int(input)

choice = raw_input("Which type of area you would like to calculate (R/T/C/Z)? -> ")
if choice == "R" or choice == "r":
____calculateArea("Rectangle")
elif choice == "T" or choice == "t":
____calculateArea("Triangle")
elif choice == "C" or choice == "c":
____calculateCircleAndTrapezoids("Circle")
elif choice == "Z" or choice == "z":
____calculateCircleAndTrapezoids("Trapezoids")
else:
____print "Please type R,T,C or Z to choose the type of area to calculate"

แบบที่ 3

def calculateArea(area,check):
____print "Program to calculate Area of ",area
____if check == "r" or check == "t":
________base = getUserInput("Please enter base -> ")
________height = getUserInput("Please enter height -> ")
________if check == "r" :
____________print "Rectangle area of base=", base, "and height=", height, "is", \
__________________base*height
________elif check == "t" :
____________print "Triangle area of base=", base, "and height=", height, "is", \
__________________0.5*base*height
____elif check == "c":
________radius = getUserInput("Please enter radius -> ")
________print "Circle area of radius=", radius, "is", 3.14159*(radius*radius)
____elif check == "z":
________parallel_base1 = getUserInput("Please enter parallel base 1-> ")
________parallel_base2 = getUserInput("Please enter parallel base 2-> ")
________height = getUserInput("Please enter height -> ")
________print "Trapezoids area of parallel base1=", parallel_base1, '\n'\
______________"parallel base2=", parallel_base2, '\n'"and height=", height,"is",\
______________0.5*(parallel_base1+parallel_base2)*height

def getUserInput(text_to_display):
____input = raw_input(text_to_display)
____return int(input)

choice = raw_input("Which type of area you would like to calculate (R/T/C/Z)? -> ")
if choice == "R" or choice == "r":
____calculateArea("Rectangle","r")
elif choice == "T" or choice == "t":
____calculateArea("Triangle","t")
elif choice == "C" or choice == "c":
____calculateArea("Circle","c")
elif choice == "Z" or choice == "z":
____calculateArea("Trapezoids","z")
else:
____print "Please type R,T,C,Z to choose the type of area to calculate "

แบบที่ 4

def getUserInput(text_to_display):
____input = raw_input(text_to_display)
____return int(input)

def calculateAREA(Area_of):
____print "Program to calculate Area of", Area_of
____if Area_of == "Circle":
________radious = getUserInput("Please enter radious -> ")
________result = 3.14159*radious*radious
____elif Area_of == "Trapezoid":
________parallel_line1 = getUserInput("Please enter length of 1st parallel line -> ")
________parallel_line2 = getUserInput("Please enter length of 2nd parallel line -> ")
________height = getUserInput("Please enter height -> ")
________result = (parallel_line1+parallel_line2)*height*0.5
____else:
________base = getUserInput("Please enter base -> ")
________height = getUserInput("Please enter height -> ")
________if Area_of == "Rectangle":
____________result = base*height
________else:
____________result = base*height*0.5
____print Area_of, "area is", result

i = 0
while i == 0:
____choice = raw_input("Which type of area you would like to calculate\
_______________________(R,T,Z or C)? -> ")
____if choice == "R" or choice == "r":
________calculateAREA("Rectangle")
________i += 1
____elif choice == "T" or choice == "t":
________calculateAREA("Triangle")
________i += 1
____elif choice == "C" or choice == "c":
________calculateAREA("Circle")
________i += 1
____elif choice == "Z" or choice == "z":
________calculateAREA("Trapezoid")
________i += 1
____else:
________print "Please type R,T,Z or C to choose the type of area to calculate."

แบบที่ 5

def calculateCircleArea():
____print "Program to calculate Area of Circle"
____radius = getUserInput("Please enter radius -> ")
____print "Circle area of radius", radius ,"is",3.14159*(radius**2)

def calculateTrapezoidsArea():
____print "Program to calculate Area of Trapezoids"
____parallel_1 = getUserInput("Please enter parallel_base1 -> ")
____parallel_2 = getUserInput("Please enter parallel_base2 -> ")
____height = getUserInput("Please enter height -> ")
____print "Trapezoids area of parallel_base1", parallel_1,\
__________"\nTrapezoids area of parallel_base2", parallel_2,"\nand height", height,\
__________"\nis", 0.5*(parallel_1+parallel_2)*height

def getUserInput(text_to_display):
____input = raw_input(text_to_display)
____return int(input)

def baseadnheight(area):
____print "Program to calculate Area of ",area
____base = getUserInput("Please enter base -> ")
____height = getUserInput("Please enter height -> ")
____if(area=="Rectangle"):
________a = base*height
____else:
________a = base*height*0.5
____print area," area of base", base,"and height", height,"is", a

choice = raw_input("Which type of area you would like to calculate (R/T/C/Z)? -> ")
if choice == "R" or choice == "r":
____baseadnheight("Rectangle")
elif choice == "T" or choice == "t":
____baseadnheight("Triangle")
elif choice == "C" or choice == "c":
____calculateCircleArea()
elif choice == "Z" or choice == "z":
____calculateTrapezoidsArea()
else:
____print "Please type R, T, C or Z to choose the type of area to calculate"

แบบที่ 6

def getUserInput(text_to_display):
____input = raw_input(text_to_display)
____return int(input)

def calculateRectangle():
____print "Program to calculate Area of Rectangle"
____base = getUserInput("Please enter base -> ")
____height = getUserInput("Please enter height -> ")
____print "Rectangle area of base", base, "and height", height, "is", base*height

def calculateTriangle():
____print "Program to calculate Area of Triangle"
____base = getUserInput("Please enter base -> ")
____height = getUserInput("Please enter height -> ")
____print "Triangle area of base", base, "and height" , height , "is",\
__________0.5*base*height

def calculateCircle():
____print "Program to calculate Area of Circle"
____radius = getUserInput("Please enter radius -> ")
____print "Circle area of radius", radius , "is", 3.14159*(radius**2)

def calculateTrapezoids():
____print "Program to calcultae Area of Trapezoids"
____parallel_base1 = getUserInput("Please enter 1st parallel base -> ")
____parallel_base2 = getUserInput("Please enter 2nd parallel base -> ")
____height = getUserInput("Please enter height -> ")
____print "Trapezoids area of parallel base", parallel_base1, parallel_base2,\
__________"and height",height, "is", 0.5*((parallel_base1+parallel_base2)*height)

choice = raw_input("Which type of area you would like to calculate (R/T/C/Z)? -> ")
if choice == "R" or choice == 'r':
____calculateRectangle()
elif choice == "T" or choice == "t":
____calculateTriangle()
elif choice == "C" or choice == "c":
____calculateCircle()
elif choice == "Z" or choice == "z":
____calculateTrapezoids()
else:
____print "Please type R, T , C or Z to choose the type of area to calculate"

1 comment:

  1. มาแล้วครับ นิตยสารฉบับ PDF ประจำเดืนมีนาคม เชิญ download ได้ตาม link ข้างล่างเลยนะครับ

    http://www.4shared.com/file/236319518/c0bbd543/THAI_Bioinformatics-March_2010.html

    มี comment อะไรเขียนมาติชมกันได้นะครับ หรือ post ไว้ก็ได้ครับ

    ReplyDelete