Table of Contents

2. ตัวแปร นิพจน์ และคำสั่ง

สิ่งที่ทรงพลังมากที่สุดสิ่งหนึ่งในภาษาของการเขียนโปรแกรม คือ การที่เราสามารถจัดการกับ ตัวแปร (variable) ตัวแปร คือ ชื่อที่ถูกอ้างถึงค่าหนึ่งๆ

(หมายเหตุผู้แปล: ค่าที่ถูกเก็บอยู่ในหน่วยความจำ)

2.1 คำสั่งที่ใช้ในการกำหนดค่า

คำสั่งกำหนดค่า จะสร้างตัวแปรตัวใหม่ขึ้นมา พร้อมให้ค่ากับตัวแปรนั้น:

>>> message = 'And now for something completely different'
>>> n = 17
>>> pi = 3.141592653589793

ตัวอย่างข้างบนนี้ได้ทำการกำหนดค่า 3 ค่า คำสั่งแรกกำหนดสายอักขระ (string) ในตัวแปรใหม่ที่ชื่อว่า message คำสั่งที่สอง กำหนดค่าจำนวนเต็ม (integer) 17 ให้กับตัวแปร n คำสั่งที่สาม กำหนดค่าประมาณของค่า $\pi$ ให้กับตัวแปรที่ชื่อว่า pi

โดยปกติแล้ว เราแสดงตัวแปรบนหน้ากระดาษโดยใช้การเขียนชื่อตัวแปรแล้วชี้ไปที่ค่าของมัน การเขียนแบบนี้เรียกว่า แผนภาพสถานะ (state diagram) เพราะว่ามันแสดงสถานะว่าค่าของตัวแปร นั้นเป็นอย่างไรในตอนนี้ (ให้ลองนึกถึงสถานะต่างๆ ที่เปลี่ยนแปลงไปของจิตของเรา) รูปที่ 2.1 แสดงให้เห็นถึงผลการให้ค่าของตัวอย่างที่แล้ว

แผนภาพสถานะ
รูปที่ 2.1 แผนภาพสถานะ

2.2 ชื่อตัวแปร

โดยทั่วไปแล้ว นักเขียนโปรแกรมเลือกชื่อสำหรับตัวแปรที่มีความหมาย—พวกเขาทำการบันทึก ว่าตัวแปรหนึ่งๆ เอาไว้ทำอะไรหรือเก็บค่าอะไร

ชื่อของตัวแปรสามารถยาวเท่าที่เราต้องการได้ ชื่อของตัวแปรสามารถมีทั้งตัวอักษรและตัวเลข แต่ชื่อนั้นไม่สามารถขึ้นต้นด้วยตัวเลขได้ จริงๆ แล้วเราสามารถขึ้นต้นชื่อตัวแปรด้วยอักษร ตัวใหญ่ได้ แต่เรานิยมเริ่มต้นด้วยอักษรตัวเล็กซะมากกว่า

ในชื่อตัวแปรนั้นสามารถมีเครื่องหมายขีดล่าง (underscore), _, ส่วนใหญ่แล้วเราจะ ใช้ชื่อตัวแปรที่มีเครื่องหมายขีดล่างในชื่อที่ประกอบด้วยคำหลายคำ เช่น your_name หรือ airspeed_of_unladen_swallow

ถ้าเราตั้งชื่อตัวแปรผิดกฎ เราจะได้ข้อผิดพลาดทางวากยสัมพันธ์ (syntax error) หรือข้อผิดพลาด เชิงกฎเกณฑ์ของภาษา

>>> 76trombones = 'big parade'
SyntaxError: invalid syntax
>>> more@ = 1000000
SyntaxError: invalid syntax
>>> class = 'Advanced Theoretical Zymurgy'
SyntaxError: invalid syntax

ชื่อตัวแปร 76trombones นั้นผิดกฎเพราะว่ามันเริ่มด้วยตัวเลข ส่วนชื่อตัวแปร more@ นั้นผิดกฎเพราะว่ามันมีอักขระต้องห้าม @ แล้วสำหรับชื่อตัวแปร class มันผิดอย่างไรกันนะ

ปรากฏว่า ชื่อตัวแปร class นั้นเป็น คำสำคัญ (keywords) ของภาษาไพธอน ตัวแปลภาษาใช้คำสำคัญเหล่านี้ในการรู้จำโครงสร้างของโปรแกรม เราจึงไม่สามารถใช้คำสำคัญเหล่านี้ ในการตั้งชื่อตัวแปรได้

ไพธอนเวอร์ชัน 3 มีคำสำคัญดังนี้:

False      class      finally    is         return
None       continue   for        lambda     try
True       def        from       nonlocal   while
and        del        global     not        with
as         elif       if         or         yield
assert     else       import     pass
break      except     in         raise

เราไม่จำเป็นต้องจำคำสำคัญเหล่านี้ทั้งหมด ในโปรแกรมที่มีสภาพแวดล้อมสำหรับการพัฒนา (development environment) ส่วนใหญ่แล้วจะแสดงคำสำคัญเหล่านี้ โดยใช้สีที่แตกต่างจาก โค้ดธรรมดา ถ้าเราพยายามจะใช้คำเหล่านี้ในโปรแกรม เราก็จะรู้ได้โดยสังเกตจากสีที่แตกต่างออกไป

2.3 นิพจน์และคำสั่ง

นิพจน์ (expression) เป็นการรวมกันของค่า ตัวแปร และตัวดำเนินการต่างๆ ค่า (value) เดี่ยวๆ ก็ถือเป็นนิพจน์ เช่นเดียวกับ ตัวแปรเดี่ยวๆ ด้วย ดังนั้น สิ่งต่างๆ ต่อไปนี้ถือเป็นนิพจน์ที่ถูกต้องตามวากยสัมพันธ์

>>> 42
42
>>> n
17
>>> n + 25
42

เมื่อเราพิมพ์นิพจน์ที่ข้อความพร้อมรับ (prompt) ตัวแปลภาษาจะทำการ ประเมินค่า (evaluates) ซึ่งหมายความว่ามันจะหาค่าของนิพจน์นั้นออกมา ในตัวอย่างนี้ n มีค่า 17 และ n + 25 มีค่าเท่ากับ 42

คำสั่ง (statement) เป็นหน่วยของโค้ดที่ทำให้เกิดการทำงานต่างๆ เช่น สร้างตัวแปร หรือแสดงค่า

>>> n = 17
>>> print(n)

บรรทัดแรกเป็นคำสั่งที่ให้ค่ากับตัวแปร n บรรทัดที่สองเป็นคำสั่งพิมพ์ ที่ใช้แสดงค่าของตัวแปร n

เมื่อเราพิมพ์คำสั่ง ตัวแปลภาษาจะ ดำเนินงาน (execute) ตามคำสั่งนั้น ซึ่งหมายความว่า มันจะทำตามที่คำสั่งนั้นบอกให้ทำ โดยทั่วไปแล้ว คำสั่ง (statement) จะไม่มีค่าใดๆ (ไม่ได้ให้ค่า หรือเก็บค่า)

2.4 โหมดสคริปต์

จนถึงตอนนี้ เราได้รันไพธอนใน โหมดโต้ตอบ (interactive mode) ซึ่งหมายความว่า เราพิมพ์โค้ดเพื่อโต้ตอบโดยตรงกับตัวแปลภาษา โหมดโต้ตอบเป็นโหมดที่ดีสำหรับการเริ่มต้นเขียนโปรแกรม แต่หากเราต้องการเขียนมากกว่าสองสามบรรทัด มันอาจจะดูงุ่มง่ามหน่อย

อีกทางเลือกในการเขียนโปรแกรม คือ การเขียนและบันทึก (save) โค้ดลงในไฟล์ที่เรียกว่า สคริปต์ (script) และให้ตัวแปลภาษาทำงานใน โหมดสคริปต์ (script mode) เพื่อที่จะปฏิบัติตามสคริปต์นั้น เรานิยมตั้งชื่อไฟล์สคริปต์โดยใช้นามสกุล .py

ถ้าเกิดเรารู้ว่าจะสร้างและรันสคริปต์บนเครื่องคอมพิวเตอร์ของเราได้อย่างไร เราก็พร้อมที่จะไปต่อแล้ว แต่หากยังไม่รู้ ผมแนะนำให้ใช้ระบบ PythonAnywhere อีกครั้ง ผมได้เขียนขั้นตอนการรัน โหมดสคริปต์ในระบบที่ http://tinyurl.com/thinkpython2e.

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

ตัวอย่างเช่น ถ้าเราเอาไพธอนเป็นเครื่องคิดเลข เราจะพิมพ์ว่า

>>> miles = 26.2
>>> miles * 1.61
42.182

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

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

miles = 26.2
print(miles * 1.61)

พฤติกรรมนี้อาจจะทำให้นักเขียนโปรแกรมงงได้ในตอนแรกๆ

โดยปกติแล้ว ไฟล์สคริปต์จะมีลำดับของคำสั่ง ถ้ามีคำสั่งในสคริปต์มากกว่าหนึ่งคำสั่ง คำสั่งจะปฏิบัติและแสดงผลออกมาทีละคำสั่งตามลำดับ (จากบนลงล่าง)

ตัวอย่างเช่น ในสคริปต์ต่อไปนี้

print(1)
x = 2
print(x)

ทำให้เกิดการแสดงผล คือ

1
2

คำสั่งกำหนดค่า (assignment statement) ไม่ได้ทำให้เกิดการแสดงผลใดๆ

เพื่อที่จะตรวจสอบความเข้าใจของเรา ให้พิมพ์คำสั่งต่อไปนี้ในตัวแปลภาษาไพธอน (โหมดโต้ตอบ) และลองดูว่ามันทำอะไรบ้าง:

5
x = 5
x + 1

คราวนี้ ให้เอาคำสั่งข้างบนเดียวกันนี้ไปใส่ในไฟล์สคริปต์ แล้วลองรันดู มันให้ผลอย่างไรบ้าง?

จากนั้น ให้แก้ไขแต่ละคำสั่งให้เป็นคำสั่งพิมพ์ (print) และลองรันดูอีกที

2.5 ลำดับการดำเนินการ

เมื่อนิพจน์ประกอบด้วยตัวดำเนินการ (operator) มากกว่าหนึ่งตัว ลำดับของการประเมินผล ค่านั้นจะขึ้นอยู่กับ ลำดับของตัวดำเนินการ (order of operations) สำหรับ ตัวดำเนินการทางคณิตศาสตร์ (mathematical operator) ไพธอนจะทำตามลำดับที่เป็น ที่นิยมกันทั่วไป โดยให้เราจำตัวย่อ PEMDAS เพื่อที่จะจำได้ง่ายขึ้น ดังนี้:

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

2.6 การดำเนินการกับสายอักขระ

โดยทั่วไปแล้ว เราไม่สามารถดำเนินการทางคณิตศาสตร์กับสายอักขระได้ แม้ว่าสายอักขระจะดูเหมือนเป็น ตัวเลขก็ตาม ดังนั้น การทำดังต่อไปนี้จะผิดพลาดเชิงวากยสัมพันธ์:

'2'-'1'    'eggs'/'easy'    'third'*'a charm'

แต่ก็มีข้อยกเว้นสำหรับ 2 อย่าง คือ เครื่องหมาย + และ

ตัวดำเนินการ + จะทำ การเชื่อมสายอักขระ (string concatenation) ซึ่งหมายความว่ามันจะเชื่อมสายอักขระสองตัวเข้าด้วยกันทางด้านท้าย เช่น:

>>> first = 'throat'
>>> second = 'warbler'
>>> first + second
throatwarbler

ตัวดำเนินการ * ยังสามารถทำงานกับสายอักขระได้ด้วย มันทำให้เกิดการทำซ้ำสายอักขระ เช่น 'Spam'*3 ให้ผลว่า 'SpamSpamSpam' ถ้าตัวถูกดำเนินการตัวใดตัวหนึ่งเป็นสายอักขระ อีกตัวหนึ่งจะต้องเป็นจำนวนเต็มเสมอ (ไม่เช่นนั้นจะเกิดข้อผิดพลาดขึ้น)

การใช้งาน + และ * ในลักษณะนี้ มันก็สอดคล้องกับการบวกและการคูณ เปรียบเทียบกับการทำ 4*3 จะให้ค่าเท่ากับ 4+4+4 เราจึงคาดว่า 'Spam'*3 ก็น่าจะให้ค่าเท่ากับ 'Spam'+'Spam'+'Spam' และมันก็เป็นเช่นนั้น ในทางกลับกัน การต่อสายอักขระและการทำซ้ำสายอักขระ ก็มีความแตกต่างอย่างมากกับการบวกและคูณจำนวนเต็ม เราลองคิดดูสิว่า มีคุณสมบัติอะไรบ้างที่การบวกจำนวนเต็มนั้นแตกต่างจากการต่อสายอักขระ

2.7 คอมเมนต์

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

จากเหตุผลดังกล่าว มันเลยเป็นการดีที่จะเพิ่มคำอธิบายโค้ดสั้นๆ เข้าไปในโปรแกรมด้วย เพื่ออธิบายให้เป็นภาษามนุษย์ ว่าโปรแกรมทำงานอะไรบ้าง คำอธิบายเหล่านี้เรียกว่า คอมเมนต์ (comments) และส่วนของคอมเมนต์จะเริ่มด้วยสัญลักษณ์ #:

# compute the percentage of the hour that has elapsed
percentage = (minute * 100) / 60

ในกรณีนี้ คอมเมนต์อยู่ในบรรทัดเดี่ยวๆ ของมันเอง นอกจากนี้เรายังสามารถใส่คอมเมนต์ เข้าไปในท้ายบรรทัดของคำสั่งต่างๆ ได้ด้วย:

percentage = (minute * 100) / 60     # percentage of an hour

ทุกอย่างตั้งแต่สัญลักษณ์ # ไปจนถึงจบบรรทัดนั้นจะถูกเมินโดยโปรแกรม— มันจะไม่มีผลกับการทำงานของโปรแกรมเลย

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

คอมเมนต์ข้างล่างนี้ซ้ำซ้อนกับโค้ดและไม่มีประโยชน์:

v = 5     # assign 5 to v

ส่วนคอมเมนต์ต่อไปนี้ มีข้อมูลที่เป็นประโยชน์ที่ไม่ได้อยู่ในโค้ด:

v = 5     # velocity in meters/second. 

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

2.8 การดีบัก

ข้อผิดพลาดในโปรแกรมสามารถเกิดได้ 3 แบบ: ข้อผิดพลาดเชิงวากยสัมพันธ์ (syntax error), ข้อผิดพลาดเวลาดำเนินการ (runtime error) และ ข้อผิดพลาดเชิงความหมาย (semantic error) เวลาเกิดข้อผิดพลาดมันจะเป็นประโยชน์ ถ้าเราสามารถแยกแยะได้ว่า เป็นความผิดพลาดประเภทใด เพื่อที่จะหาสาเหตุได้เร็วขึ้น

ข้อผิดพลาดเชิงวากยสัมพันธ์ (Syntax error):

“syntax” หมายความถึงโครงสร้างของ โปรแกรม และกฎเกณฑ์ต่างๆ ที่เกี่ยวกับโครงสร้างนั้น เช่น วงเล็บจะต้องมีคู่เปิดปิดให้ครบ ดังนั้น (1 + 2) จะถูกกฎ แต่ 8) จะเป็นข้อผิดพลาดเชิงวากยสัมพันธ์

หากเกิดข้อผิดพลาดเชิงวากยสัมพันธ์สักแห่งในโปรแกรม ไพธอนจะแสดงข้อความระบุข้อผิดพลาด (error message) และออกจากโปรแกรมไป และเราก็จะไม่สามารถรันโปรแกรมนั้นได้ ในช่วงเวลาที่เราเริ่มฝึกเขียน 2-3 สัปดาห์แรก เราอาจจะต้องเวลามากในการหาสาเหตุของข้อผิดพลาดเชิงวากยสัมพันธ์ แต่เมื่อเรามี ประสบการณ์ในการเขียนโปรแกรมมากขึ้นแล้ว เราอาจจะมีข้อผิดพลาดเหล่านี้น้อยลงและหาต้นตอได้เร็วขึ้น

ข้อผิดพลาดตอนดำเนินการ (Runtime error):

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

ข้อผิดพลาดตอนดำเนินการนั้น เกิดได้ยากในโปรแกรมพื้นฐานที่เราจะได้เห็นใน 2-3 บทแรกนี้ ดังนั้น อีกสักพักเลยเราถึงจะเจอข้อผิดพลาดแบบนี้

ข้อผิดพลาดเชิงความหมาย (Semantic error):

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

(หมายเหตุผู้แปล: อาจจะไม่ใช่สิ่งที่เราต้องการทำจริงๆ คือ เราบอกมันผิดจากที่เราต้องการนั่นเอง)

การระบุข้อผิดพลาดเชิงความหมายอาจจะลำบากหน่อย เพราะเราจะต้องกลับไปไล่ดูผลการทำงานของโปรแกรม และพยายามที่จะหาว่าโปรแกรมมันทำอะไรกันแน่ (และทำพลาดตรงไหน)

2.9 อภิธานศัพท์

2.10 แบบฝึกหัด

แบบฝึกหัด 1
ขอย้ำคำแนะนำจากบทที่แล้ว เมื่อไหร่ก็ตามที่เราได้เรียนรู้ลักษณะเฉพาะใหม่ๆ ของภาษา เราควรที่จะต้องทดลองในโหมดโต้ตอบ และลองทำให้เกิดข้อผิดพลาดต่างๆ เพื่อที่จะดูว่าจะเกิดอะไรขึ้นได้บ้าง

แบบฝึกหัด 2
ให้ฝึกการใช้ตัวแปลภาษาไพธอนให้เป็นเครื่องคิดเลข:

  1. ปริมาตรของทรงกลมที่มีรัศมี $r$ คือ $\frac{4}{3} \pi r^3$ แล้วปริมาตรของทรงกลมที่มีรัศมีเท่ากับ 5 เป็นเท่าไหร่
  2. สมมติว่า ราคาหน้าปกหนังสือ คือ \$24.95 แต่ร้านหนังสือลดราคาให้ 40% ค่าส่งหนังสือ คือ \$3 สำหรับเล่มแรก และ 75 เซ็นต์ (\$0.75) สำหรับแต่ละเล่มที่เพิ่มขึ้นมา ราคาของการซื้อหนังสือ จำนวน 60 เล่มจะเป็นเท่าไหร่
  3. ถ้าเราออกจากบ้านในเวลา 6:52 และวิ่ง 1 ไมล์แบบเบาๆ (8:15 นาทีต่อไมล์) จากนั้นวิ่งทำเวลาเป็นจำนวน 3 ไมล์ (7:12 นาทีต่อไมล์) และจบด้วยวิ่งเบาๆ อีก 1 ไมล์ แล้วเราจะได้กลับบ้านไปกินข้าวเช้าในเวลาใด

https://greenteapress.com/thinkpython2/html/thinkpython2003.html