ตั้งแต่ไพธอน 3 ถูกปล่อยออกมาในปี 2008 ก็มีเสียงวิพากย์วิจารณ์มากมายว่ามีความแตกต่างไปจากไพธอน 2 มากเกินไปจนทำให้สูญเสียความเข้ากันได้
โค้ดที่เขียนด้วยไพธอน 2 ไม่สามารถนำมาใช้ในไพธอน 3 ได้โดยไม่มีการปรับแก้ ด้วยเหตุนี้จึงมีคนมากมายยังคงนิยมใช้ไพธอน 2 ต่อไปโดยไม่เคยคิดจะเปลี่ยนมาใช้ไพธอน 3
แม้ว่าคนที่เพิ่งมาศึกษาภาษาไพธอนเอาช่วงหลังๆมานี้มักจะได้รับคำแนะนำให้ศึกษาไพธอน 3 มากกว่า แต่ถึงอย่างนั้นไพธอน 2 ก็ยังเป็นที่นิยมมากกว่าอยู่ ดังนั้นจึงจำเป็นต้องเรียนรู้ไว้บ้าง
หากทำความเข้าใจเรื่องความแตกต่างระหว่างไพธอน 2 และ 3 ได้แล้ว ไม่ว่าจะเริ่มศึกษาจากเวอร์ชันไหนก็สามารถเปลี่ยนไปใช้อีกเวอร์ชันได้ไม่ยากเย็น
- การตั้งชื่อตัวแปร
- ชนิดข้อมูลจำนวนเต็ม
- การใช้เลขนอกเหนือจากเลขฮินดูอารบิกเป็นค่าตัวเลข
- ฟังก์ชัน print
- ฟังก์ชัน input
- การหารจำนวนเต็ม
- การยกกำลังจำนวนติดลบ
- ชนิดข้อมูลของสายอักขระ
- ชนิดข้อมูลของ range
- การจัดการกับตัวแปรที่ใช้ใน for
- เมธอด keys, values และ items ของดิกชันนารี
- ฟังก์ชัน map, filter และ zip
- การใช้ฟังก์ชัน super
- ออบเจ็กต์ของความผิดพลาดในโครงสร้าง try except
- เมธอด next กับ __next__
- มอดูล __future__
การตั้งชื่อตัวแปร
ในไพธอน 2 ชื่อตัวแปรจะใช้ได้แค่อักษรโรมัน ๒๖ ตัวหลัก (ทั้งพิมพ์ใหญ่และพิมพ์เล็ก) และตัวเลข 0 ถึง 9 แล้วก็สัญลักษณ์ขีดล่าง _
แต่ในไพธอน 3 สามารถตั้งชื่อเป็นอักษรชนิดอื่นได้ เช่น
- อักษรโรมันที่มีสัญลักษณ์เพิ่มเติม (áéíóúýäëïöüÿøåæñ ฯลฯ)
- อักษรกรีก (αβγδεζηθικλμνξοπρστυφχψω ฯลฯ)
- อักษรไทย ลาว เขมร เวียดนาม จีน ญี่ปุ่น เกาหลี ฯลฯ (ไทย ລາວ ខ្មែរ Việt 漢字 カタカナ ひらがな 한글 ฯลฯ)
- และอื่นๆอีกมากมาย
การที่สามารถตั้งชื่อตัวแปรได้หลากหลายขึ้นก็อาจช่วยให้การใช้งานยืดหยุ่นขึ้นได้ดี
ตัวอย่าง ลองพิมพ์
จำนวนจังหวัดทั้งหมดในประเทศไทย = 77
ในไพธอน 3 จะไม่มีอะไรเกิดขึ้น ข้อความยาวๆนี้ได้รับการยอมรับให้เป็นชื่อตัวแปร และเก็บค่าตัวเลขไปเรียบร้อย แต่ในไพธอน 2 จะขึ้นว่า
SyntaxError: invalid syntax
ชนิดข้อมูลจำนวนเต็ม
ในไพธอน 2 นั้นจำนวนเต็มถูกแบ่งเป็น ๒ ชนิดคือ int กับ long แต่ในไพธอน 3 ได้รวมกันเป็นชนิดเดียวคือ int
โดยค่า int จะมีขอบเขตจำกัดอยู่ค่าหนึ่ง
ค่าสูงสุดของ int นั้นมีจำกัดอยู่แล้วแต่เครื่องโดยอาจจะเป็น 2 ยกกำลัง 63 ลบ 1 หรือ 2 ยกกำลัง 31 ลบ 1
ลองพิมพ์
import sys
print(sys.maxint)
ก็จะได้ค่าสูงสุดของ int ออกมา
ลองพิมพ์ลงในเชลโต้ตอบไปตามนี้
2**80
ในไพธอน 3 จะได้ผลลัพธ์เป็น
1208925819614629174706176
แต่ในไพธอน 2 จะได้ผลลัพธ์เป็น
1208925819614629174706176L
สิ่งที่ต่างกันคือในไพธอน 2 มีตัว L โผล่เพิ่มขึ้นมา ซึ่งตัว L ในที่นี้เป็นตัวบ่งบอกว่าเป็นข้อมูลชนิด long นั่นเอง
หมายความว่าในไพธอน 2 ถ้าหากใส่เลขที่ใหญ่เกินขอบเขตที่จะเป็น int ได้ก็จะถูกเก็บในรูปของ long
ในขณะที่ในไพธอน 3 จะใหญ่แค่ไหนก็ยังเป็น int อยู่ดี และจะไม่มีข้อมูลชนิด long
ดังนั้นหากพิมพ์ 1208925819614629174706176L ลงในไพธอน 3 ก็จะขึ้นว่า
SyntaxError: invalid syntax
การใช้เลขนอกเหนือจากเลขฮินดูอารบิกเป็นค่าตัวเลข
ในไพธอน 2 นั้นหากจะแปลงสายอักขระที่เก็บตัวเลขให้เป็นข้อมูลชนิดจำนวนตัวเลขจะต้องใช้เลขฮินดูอารบิกเท่านั้น เช่น
int('12') # ได้ 12
แต่ในไพธอน 3 อาจใช้เลขไทยหรือเลขอื่นๆได้อีกหลายชนิด หรืออาจใช้ปนกันก็ได้ เช่น
int('๑๒') # ได้ 12
float('๑๒.๒') # ได้ 12.2
float('๑2.๒2') # ได้ 12.22
เพียงแต่ว่ายังไงก็จำเป็นต้องเขียนเป็นสายอักขระแล้วแปลงเป็นตัวเลขอีกที ไม่สามารถนำมาคำนวณโดยตรง เช่น
๑+๑
ได้
SyntaxError: invalid character in identifier
ต้องเขียนเป็น
int('๑')+int('๑') # ได้ 2
นอกจากเลขไทยแล้วยังใช้ตัวเลขของภาษาอื่นได้อีกหลายชนิด เช่น ลาว เขมร พม่า เพียงแต่ว่าเลขจีนไม่สามารถใช้ได้
นี่ก็ถือเป็นรายละเอียดปลีกย่อยเล็กๆอย่างหนึ่งที่ถูกเพิ่มเข้ามา
ฟังก์ชัน print
เรื่องการใช้คำสั่ง print นี้เป็นตัวอย่างหนึ่งของความเปลี่ยนแปลงที่ถูกยกมาพูดถึงบ่อยที่สุด
เดิมทีในไพธอน 2 คำสั่ง print มีโครงสร้างการใช้แบบนี้
print 'sawatdi'
นั่นคือ print แล้วเว้นวรรค ตามด้วยสิ่งที่ต้องการแสดงผลออกมา
แต่ว่าในไพธอน 3 ได้ถูกเปลี่ยนกลายเป็นแบบนี้
print('sawatdi')
ก็คือจำเป็นที่นะต้องใส่วงเล็บครอบสิ่งที่ต้องการแสดงผลออกมา หากไม่ใส่ก็จะขัดข้องไม่สามารถรันได้
อัน ที่จริงความเปลี่ยนแปลงนี้มีความหมายมากถึงระดับโครงสราง เพราะในไพธอน 2 print ถือว่าเป็นแค่คำสั่งหนึ่ง ไม่ใช่ฟังก์ชัน จึงมีรูปแบบการทำงานคล้ายกับ for หรือ while คือใช้การจัดวางโดยอาจจะเว้นวรรคหรือใส่วงเล็บก็ได้
แต่ในไพธอน 3 ถือว่ากลายเป็นฟังก์ชันไปโดยสมบูรณ์ เมื่อเป็นฟังก์ชันก็จะต้องมีวงเล็บ ( ) และสิ่งที่ต้องการพิมพ์ก็มีสถานะเป็นอาร์กิวเมนต์ของฟังก์ชัน
หากลองพิมพ์
type(print)
ในไพธอน 3 ก็จะได้ผลลัพธ์เป็น
builtin_function_or_method
แต่หากลองพิมพ์ในไพธอน 2 จะได้
SyntaxError: invalid syntax
ดังนั้นจะเห็นได้ว่าการเปลี่ยนแปลงวิธีการเขียนนี้เกิดขึ้นจากการเปลี่ยนแปลงไวยากรณ์ของภาษา
อนึ่ง ที่จริงแล้วในในไพธอน 2 จะใส่วงเล็บก็ได้เหมือนกัน เพียงแต่ว่าหากมีจุลภาค , อยู่ในข้อความจะให้ผลที่แตกต่างจากไพธอน 3
ลองเปรียบเทียบ
print('nǐhǎo','konnichiwa')
ในไพธอน 3 ได้ผลเป็น
nǐhǎo konnichiwa
ส่วนในไพธอน 2 ได้ผลเป็น
('n\xc7\x90h\xc7\x8eo', 'konnichiwa')
นั่นคือผลออกมาเป็นทูเพิล แทนที่จะเป็นข้อความต่อกัน จะเห็นได้ว่าการใส่วงเล็บถูกตีความไปต่างกัน
แน่นอนว่าเมื่อใส่วงเล็บแล้วได้ทูเพิล หากลองใส่เป็นวงเล็บเหลี่ยมเช่น
print['nǐhǎo','konnichiwa']
ผลที่ได้ก็จะกลายเป็นลิสต์
ในขณะที่ถ้าต้องการให้แสดงผลเหมือนกับในไพธอน 3 ก็จะต้องไม่ใส่วงเล็บ นั่นคือ
print'nǐhǎo','konnichiwa'
อย่างไร ก็ตาม ความเปลี่ยนแปลงนี้เกิดขึ้นที่คำสั่ง print แต่สำหรับ if และ while ไม่มีอะไรเปลี่ยนแปลง ยังคงสามารถใส่หรือไม่ใส่วงเล็บก็ได้
อีกเรื่องหนึ่งคือการพิมพ์เพื่อให้ขึ้นบรรทัดต่อ ถ้าเป็นในไพธอน 3 พิมพ์เป็น
print('ความรักก็เป็นแค่ bug อย่างหนึ่ง', end='')
print('ที่เกิดขึ้นจากปฏิกิริยาทางไฟฟ้าในสมองเท่านั้น')
ได้ผลเป็น
ความรักก็เป็นแค่ bug อย่างหนึ่งที่เกิดขึ้นจากปฏิกิริยาทางไฟฟ้าในสมองเท่านั้น
แต่ในไพธอน 2 ต้องพิมพ์เป็น
print'ความรักก็เป็นแค่ bug อย่างหนึ่ง',
print'ที่เกิดขึ้นจากปฏิกิริยาทางไฟฟ้าในสมองเท่านั้น'
ได้ผลเป็น
ความรักก็เป็นแค่ bug อย่างหนึ่ง ที่เกิดขึ้นจากปฏิกิริยาทางไฟฟ้าในสมองเท่านั้น
(ที่มาของข้อความ http://hinaboshi.com/walidet/620548994630542)
ฟังก์ชัน input
ในไพธอน 2 นั้นฟังก์ชัน input จะเป็นการใส่ข้อมูลที่เป็นตัวเลข แต่หากจะใส่สายอักขระต้องเป็น raw_input
แต่ในไพธอน 3 ถูกแก้ให้ input เป็นการนำเข้าสายอักขระเท่านั้น และฟังก์ชัน raw_input ก็หายไป ไม่สามารถใช้ได้แล้ว
ยกตัวอย่าง เช่น
a = input()
แล้วลองพิมพ์ข้อความอะไรก็ได้เข้าไปโดยที่ไม่ใส่เครื่องหมายคำพูดคร่อม
ในไพธอน 3 จะไม่มีอะไรเกิดขึ้น ค่าของสายอักขระเข้าไปเก็บในตัวแปร a ตามปกติ แต่ในไพธอน 2 จะขึ้นว่า
NameError: name 'ข้อความอะไรก็ได้' is not defined
แต่ก็สามารถใส่สายอักขระได้โดยใส่เครื่องหมายคำพูดคร่อม
สรุปแล้วคือฟังก์ชัน input ในไพธอน 2 สามารถใส่ข้อมูลได้ทุกชนิด
ในขณะที่ในไพธอน 3 นั้นข้อมูลที่พิมพ์ไปจะกลายเป็นสายอักขระไปหมด แม้ว่าจะพิมพ์ตัวเลขก็ตาม
เช่นใส่ 12 ลงไปจากนั้น print(a) ถ้าเป็นไพธอน 3 จะได้เป็น '12' ออกมา คือเป็นสายอักขระที่เก็บอักษรตัวเลข 1 และ 2
ในขณะที่ถ้าเป็นไพธอน 2 จะได้เป็น 12 ซึ่งเป็นตัวเลขเลย
ในไพธอน 3 หากต้องการจะได้เป็นตัวเลขก็ต้องแปลงอีกต่อ เช่น
a = int(input())
b = float(input())
ความแตกต่างตรงนี้จำเป็นจะต้องระวังให้ดี เพราะให้ผลแตกต่างกันมากพอสมควร
การหารจำนวนเต็ม
ในไพธอน 2 นั้นจำนวนเต็มหารจำนวนเต็มจะได้จำนวนเต็มเช่นเดิม และหากเหลือเศษจะมีการปัดเศษให้เป็นจำนวนเต็ม
แต่ในไพธอน 3 จำนวนเต็มหารจำนวนเต็มจะได้จำนวนจริง ซึ่งมีทศนิยมได้ ดังนั้นจะไม่มีการปัดเศษ
ยกตัวอย่าง
print(5/3)
ในไพธอน 3 จะได้
1.6666666666666667
นั่นคือข้อมูลถูกเปลี่ยนเป็นจำนวนจริงซึ่งมีทศนิยมได้
ส่วนในไพธอน 2 จะได้
1
นั่น คือยังคงเป็นจำนวนเต็มอยู่ หารแล้วเศษจะโดนปัดทิ้งไปหมด โดยการปัดเศษนี้ไม่ใช่การปัดแบบประมาณค่า แต่เป็นการเอาเศษออกให้หมด แม้ว่าเศษนั้นจะเกิน 0.5 ก็ถูกปัดลง
นี่เป็นข้อแตกต่างสำคัญที่อาจ ต้องจำเอาไว้ เวลาที่ไปเขียนภาษาอื่นก็จะเจอทั้งภาษาที่มีการปัดและไม่มีการปัด อาจต้องจำแยก แต่หากไม่อยากวุ่นวายขอแนะนำว่าให้แปลงเป็นเลขจำนวนจริงทุกครั้งที่รู้ว่า หารแล้วอาจมีเศษ เพราะหากใช้ไพธอน 3 จนชินแล้วพอไปใช้ไพธอน 2 แล้วไปใช้ความเคยชินแบบเดิมก็จะได้ผลการคำนวณที่ผิดพลาดได้
สามารถแก้ปัญหาในไพธอน 2 ได้ไม่ยาก ด้วยการเติมจุดทศนิยมหลังจำนวนใดจำนวนหนึ่งที่ร่วมคำนวณ
5./3
เท่านี้ก็จะได้ผลเป็นจำนวนที่มีทศนิยมแล้ว
การยกกำลังจำนวนติดลบ
ในโลกของความเป็นจริงแล้วจำนวนติดลบก็สามารถยกกำลังได้ เพียงแต่จะออกมาเป็นจำนวนเชิงซ้อน
แต่ในไพธอน 2 หากจำนวนติดลบยกกำลังก็จะขัดข้องทันที ในขณะที่ในไพธอน 3 จะเปลี่ยนเป็นข้อมูลชนิดจำนวนเชิงซ้อนให้เลย เช่น
(-2)**1.1
ในไพธอน 3 ได้
(-2.0386342710747223-0.6623924280875919j)
แต่ในไพธอน 2 ได้
ValueError: negative number cannot be raised to a fractional power
ใน ไพธอน 2 จำนวนจริงไม่ถูกเปลี่ยนเป็นจำนวนเชิงซ้อนโดยอัตโนมัติ จึงจำเป็นต้องเปลี่ยนชนิดข้อมูลให้เป็นจำนวนเชิงซ้อนก่อน โดยเขียนเป็น
complex(-2)**1.1
หรือ
(-2+0j)**1.1
ชนิดข้อมูลของสายอักขระ
รายละเอียดแยกเขียนเอาไว้ใน https://phyblas.hinaboshi.com/20151219
ชนิดข้อมูลของ range
รายละเอียดแยกเขียนเอาไว้ใน https://phyblas.hinaboshi.com/20151218
การจัดการกับตัวแปรที่ใช้ใน for
ในไพธอน 3 เมื่อใช้คำสั่ง for สำหรับสร้างลิสต์ ตัวแปรนั้นจะถูกแยกออกเป็นคนละโลกกับตัวแปรภายนอก กล่าวคือต่อให้ชื่อตัวแปรซ้ำกันก็จะไม่กระทบต่อตัวแปรนั้นที่อยู่นอกคำสั่ง สร้างลิสต์ เช่น
i=10
print('ค่า i ก่อน for:', i)
print('ค่า i ใน for:', [i for i in range(5)])
print('ค่า i หลัง for:', i)
จะได้ผลลัพธ์เป็น
ค่า i ก่อน for: 10
ค่า i ใน for: [0, 1, 2, 3, 4]
ค่า i หลัง for: 10
เพราะ กรณีนี้ตัวแปร i ที่นิยามก่อนเริ่มใช้คำสั่ง for สร้างลิสต์ กับตัวแปร i ที่อยู่ในคำสั่งนั้นเป็นคนละตัวกัน ดังนั้นต่อให้สร้างลิสต์เสร็จค่า i ที่นิยามขึ้นก่อนหน้าก็ไม่มีการเปลี่ยนแปลง
แต่ถ้าเป็นในไพธอน 2 จะไม่เป็นเช่นนั้น
i=10
print 'ค่า i ก่อน for:', i
print 'ค่า i ใน for:', [i for i in range(5)]
print 'ค่า i หลัง for:', i
ผลลัพธ์
ค่า i ก่อน for: 10
ค่า i ใน for: [0, 1, 2, 3, 4]
ค่า i หลัง for: 4
เพียง แต่ว่าความเปลี่ยนแปลงนี้เกิดเฉพาะสำหรับ for ที่ใช้สร้างลิสต์เท่านั้น สำหรับการใช้ for เป็นคำสั่งวนซ้ำยังทำให้เกิดการเปลี่ยนแปลงค่าตัวแปรเช่นเดิม
ไพธอน 3
i=10
print('ค่า i ก่อน for:', i)
print('ค่า i ใน for:',end=' ')
for i in range(5): print(i,end=' ')
print('\nค่า i หลัง for:', i)
ผลลัพธ์
ค่า i ก่อน for: 10
ค่า i ใน for: 0 1 2 3 4
ค่า i หลัง for: 4
ไพธอน 2
i=10
print 'ค่า i ก่อน for:', i
print 'ค่า i ใน for:',
for i in range(5): print i,
print '\nค่า i หลัง for:', i
ผลลัพธ์
ค่า i ก่อน for: 10
ค่า i ใน for: 0 1 2 3 4
ค่า i หลัง for: 4
จะเห็นว่าไม่มีการเปลี่ยนแปลง เพราะค่าของตัวแปร i ที่เปลี่ยนไปตามการวนซ้ำถือเป็นตัวเดียวกับ i ที่นิยามก่อนหน้านั้น
เมธอด keys, values และ items ของดิกชันนารี
ในไพธอน 2 เมธอด keys, values และ items จะคืนค่าลิสต์ของคีย์, ค่า และ ทูเพิลของคีย์และค่า ตามลำดับ เช่น
dic = {'a': 5, 'b': 3, 'd': 7}
print(dic.keys())
print(dic.values())
print(dic.items())
ได้
['a', 'b', 'd']
[5, 3, 7]
[('a', 5), ('b', 3), ('d', 7)]
แต่ในไพธอน 3 จะคืนค่าของข้อมูลซึ่งเป็นตัวชี้ถึงค่าในดิกชันนารี โดยจะได้เป็นออบเจ็กต์ชนิด dict_keys, dict_values และ dict_items
dict_keys(['d', 'b', 'a'])
dict_values([7, 3, 5])
dict_items([('d', 7), ('b', 3), ('a', 5)])
ซึ่งความจริงแล้วผลนี้เทียบเท่ากับเมธอด viewkeys, viewvalues และ viewitems ในไพธอน 2
print(dic.viewkeys())
print(dic.viewvalues())
print(dic.viewitems())
ได้
dict_keys(['a', 'b', 'd'])
dict_values([5, 3, 7])
dict_items([('a', 5), ('b', 3), ('d', 7)])
แต่ในไพธอน 3 เมธอดเหล่านี้ได้หายไป ถ้าพิมพ์แบบเดียวกันในไพธอน 3 จะขึ้นว่า
AttributeError: 'dict' object has no attribute 'viewkeys'
หากต้องการให้ผลของ keys, values และ items ในไพธอน 3 เหมือนอย่างในไพธอน 2 ก็อาจทำได้โดยแปลงเป็นลิสต์ด้วยฟังก์ชัน list อีกที
print(list(dic.keys()))
print(list(dic.values()))
print(list(dic.items()))
หรืออาจไม่มีความจำเป็นต้องแปลง หากนำไปใช้เช่นใช้กับ for ก็ใช้งานได้เหมือนกับลิสต์
for s in dic.items(): print(s, end=' ')
ได้
('d', 7) ('b', 3) ('a', 5)