Tutorial

For-Loop ใน Python ทำงานยังไง?

By Arnon Puitrakul - 17 กุมภาพันธ์ 2022

For-Loop ใน Python ทำงานยังไง?

เรื่องที่น่าสนใจ และ หลาย ๆ คนมองข้ามไปคือเรื่องพื้นฐานมาก ๆ อย่าง For-Loop หรือ Loop อื่น ๆ อย่าง While Loop เราก็ใช้กันบ่อยนะ ใช้กันแทบจะทุกโปรแกรมเลย แต่เราเคยสงสัยกันมั้ยว่า เบื้องหลังของมัน มันทำงานยังไงถึงออกมาให้เราใช้งานได้แบบนี้ โดยของที่ถือว่าเป็น Foundation ในเรื่องนี้คือ Iterable และ Iterator

Iterable

Iterable ถ้าจะให้อธิบายง่าย ๆ คือ Object ที่มีความสามารถในการ Iterate หรือง่ายกว่านั้นอีก คือมันสามารถ Return สมาชิกของมันในแต่ละรอบได้ ถ้าเราเขียน Python มา พวกนี้มันก็คืออะไรก็ตามที่เราสามารถ Loop ใส่มันได้นั่นเอง

>>> iter("Hello World")
<str_iterator object at 0x102b09e20>

>>> iter([1,2,3,4])
<list_iterator object at 0x102b26070>

>>> iter(10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable

ตัวอย่างเช่น String ใน Python มันก็จะประกอบด้วย Character หลาย ๆ ตัวต่อกัน การ Iterate ก็คือการที่มันพ่น Character ที่อยู่ใน String ออกมาในแต่ละรอบนั่นเอง ซึ่งถ้า Object ไหนที่เป็น Iterable Object เราสามารถยัดมันใส่ Function ที่ชื่อว่า iter() ได้ จากตัวอย่างสุดท้ายเราจะเห็นว่า มันไม่สามารถ Iterate ได้ เพราะ Integer ไม่ใช่ Iterable Object นั่นเอง

Iterator

>>> hello_iter = iter("Hello World")

>>> next(hello_iter)
'H'

>>> next(hello_iter)
'e'

ณ ตอนนี้เรามี Object ที่สามารถ Iterate ได้แล้ว ก็คือ Iterable แล้วถามว่า ใครจะที่จะเป็นคนไล่รันเอาค่าสมาชิกออกมา สิ่งนั้นก็คือ Iterator มองภาพง่าย ๆ ว่ามันเป็นเครื่องจักรที่เอาค่าออกมา จากใน iter() ตัวมันเอง มันก็ทำอะไรไม่ได้ แต่มันจะเริ่มโยนสมาชิกออกมาก็ต่อเมื่อเราเรียกอีกคำสั่งนึง นั่นคือ next()

>>> next(hello_iter)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

แต่แน่นอนว่าจำนวนสมาชิกมันไม่ได้มีไม่อั้น มันมีจำกัด อย่างใน String "Hello World" ก็มีสมาชิก 11 ตัวด้วยกัน เมื่อเราเรียก next() ไปเรื่อย ๆ จนถึงครั้งที่ 12 ตัว Python จะดัน Exception ออกมาว่าเป็น StopIteration Exception ขึ้นมา ซึ่งเราสามารถเอา Try...Except มาจับได้

>>> list_iter = iter([1,2])
>>> next(list_iter)
1

>>> next(hello_iter)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

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

เรื่องนี้เราสามารถอธิบายได้จากวิธีการสร้าง Iterable บน Class โดยที่ Class นั้น ๆ จะเป็น Iterable ได้ มันจะต้องมีการ Implement Dunder Method ที่ชื่อว่า __iter__ ลงไปด้วย แล้วเมื่อเราสร้างออกมาเป็น Object ไม่ว่าเราจะสร้างออกมากี่อัน แต่จะตัว มันก็จะมีการจัดการ State ในตัวของมันเอง เหมือนกับที่เราสามารถใส่ค่าใน Attribute ที่ไม่เหมือนกันได้นั่นเอง

How for-loop works?

หลังจากเราเข้าใจ Concept ของคำว่า Iterable และ Iterator แล้ว เรามาดูคำตอบกันว่าจริง ๆ แล้ว For-Loop เขาทำงานยังไงใน Python เราอยากให้ลองเอาสิ่งที่เราเล่าเมื่อกี้มาคิดดูก่อนว่า มันน่าจะทำอย่างไร ถึงออกมาเป็น For-Loop ได้...... โอเค เฉลย

ขั้นตอนของมันจริง ๆ คือ มันจะแปลง Iterable ให้เป็น Iterator ก่อนผ่านคำสั่ง iter() จากนั้น มันก็จะเรียก next() ของ Iterator ที่สร้างเอาไว้ ทำแบบนี้ไปเรื่อย ๆ จนกว่าจะได้ StopIteration ออกมา มันก็จะออกจาก Loop นั่นเอง อื้อ แค่นั้นเลย....

สรุป

วันนี้เรามาเล่าในหลังม่านการทำงานของ For-Loop ทั้งหลาย ซึ่งมันใช้ 2 ส่วนในการทำให้มันเกิดขึ้นได้คือ Iterable และ Iterator ทำงานเข้าด้วยกัน โดยที่ทั้ง 2 อย่างนี้มีความแตกต่างกัน คือ Iterable คือ Object ที่สามารถ Iterate ได้ ส่วน Iterator เป็นเหมือนเครื่องจักรในการพ่นค่าสมาชิกใน Iterable ออกมานั่นเอง เอาจริง ๆ แล้ว หลาย ๆ คนอาจจะมองว่ามันเป็นเรื่องที่ เออ รู้ทำไมอะ เราว่ามันทำให้เออรู้สึกว่า Python มันเป็นภาษาที่แปลกดีนะ มันใช้วิธีแบบนี้เพื่อให้มันเข้าใจได้ง่าย และ นำไปใช้ได้ง่าย

Read Next...

จัดการข้อมูลบน Pandas ยังไงให้เร็ว 1000x ด้วย Vectorisation

จัดการข้อมูลบน Pandas ยังไงให้เร็ว 1000x ด้วย Vectorisation

เวลาเราทำงานกับข้อมูลอย่าง Pandas DataFrame หนึ่งในงานที่เราเขียนลงไปให้มันทำคือ การ Apply Function เข้าไป ถ้าข้อมูลมีขนาดเล็ก มันไม่มีปัญหาเท่าไหร่ แต่ถ้าข้อมูลของเราใหญ่ มันอีกเรื่องเลย ถ้าเราจะเขียนให้เร็วที่สุด เราจะทำได้โดยวิธีใดบ้าง วันนี้เรามาดูกัน...

ปั่นความเร็ว Python Script เกือบ 700 เท่าด้วย JIT บน Numba

ปั่นความเร็ว Python Script เกือบ 700 เท่าด้วย JIT บน Numba

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

Humanise the Number in Python with "Humanize"

Humanise the Number in Python with "Humanize"

หลายวันก่อน เราทำงานแล้วเราต้องการทำงานกับตัวเลขเพื่อให้มันอ่านได้ง่ายขึ้น จะมานั่งเขียนเองก็เสียเวลา เลยไปนั่งหา Library มาใช้ จนไปเจอ Humanize วันนี้เลยจะเอามาเล่าให้อ่านกันว่า มันทำอะไรได้ แล้วมันล่นเวลาการทำงานของเราได้ยังไง...

ทำไม 0.3 + 0.6 ถึงได้ 0.8999999 กับปัญหา Floating Point Approximation

ทำไม 0.3 + 0.6 ถึงได้ 0.8999999 กับปัญหา Floating Point Approximation

การทำงานกับตัวเลขทศนิยมบนคอมพิวเตอร์มันมีความลับซ่อนอยู่ เราอาจจะเคยเจอเคสที่ เอา 0.3 + 0.6 แล้วมันได้ 0.899 ซ้ำไปเรื่อย ๆ ไม่ได้ 0.9 เพราะคอมพิวเตอร์ไม่ได้มองระบบทศนิยมเหมือนกับคนนั่นเอง บางตัวมันไม่สามารถเก็บได้ เลยจำเป็นจะต้องประมาณเอา เราเลยเรียกว่า Floating Point Approximation...