Python: range is not an iterator!
หลายคนเข้าใจว่า range
ในภาษา Python เป็น Iterator แต่ความเป็นจริงนั้นไม่ใช่
ภาษา Python มีศัพท์สองคำที่เกี่ยวข้องกับการวนลูปได้ คำแรกคือ Iterables
อะไรที่ไล่วนลูปได้ก็คือสิ่งนี้ เช่น List และ Tuple เป็นต้น โดยอาศัยความสามารถของ Iterators
หรือตัวที่ใช้สำหรับการวนลูปเป็นผู้เล่นสำคัญในการคืนค่าแต่ละครั้งของการวนลูป
1# [1, 2] เป็น List มีความสามารถเป็น Iterable2# ใช้ iter เพื่อดึง Iterator ออกจาก Iterable ได้3my_iterator = iter([1, 2])4วนลูปได้ข้อมูลแต่ละค่าผ่านการเรียก next ไปที่ Iterator5next(my_iterator) # 16next(my_iterator) # 27next(my_iterator)8# เมื่อค่าข้อมูลสิ้นสุด Python จะทำการโยน StopIteration ออกมา9# Traceback (most recent call last):10# File "<stdin>", line 1, in <module>11# StopIteration
Iterators มีคุณสมบัติในการเป็น Iterables อีกด้วย นั่นคือเราสามารถใช้ iter
เพื่อดึง Iterator ออกมาจาก Iterator นั้นๆ ซึ่งค่าที่ได้ก็คือตัวมันเอง
คุณสมบัติอีกประการที่สำคัญคือ เมื่อทำการวนลูปครบทุกค่าแล้วเราจะไม่ได้ค่าอะไรอีกจาก Iterator นั้น
1my_iterator = iter([1, 2])2# วนลูปเพื่อสร้าง list3[x**2 for x in my_iterator] # [1, 4]4# ใช้ทุกค่าหมดไปแล้ว รอบถัดไปไม่คืนค่าใดๆ อีก5[x**2 for x in my_iterator] # []
แต่ range
ก็วนลูปได้นะ แสดงว่าเราเรียก iter
เพื่อดึง Iterator ออกมาได้ แล้ว range
จะเป็น Iterator ด้วยรึเปล่า? เพื่อเป็นการพิสูจน์เราจะลองทดสอบ range
ในฐานะของ Iterator กัน
1# ถ้า range เป็น Iterator ต้องสามารถใช้คู่กับ next ได้2next(range(3)) # TypeError: 'range' object is not an iterator34numbers = range(3)5tuple(numbers) # (0, 1, 2)6# ถ้า range เป็น Iterator เมื่อวนครบทุกค่าแล้ว ไม่ควรได้ค่าใดออกมาอีก7tuple(numbers) # (0, 1, 2)
จบนะ! สรุปแล้ว range
ไม่ใช่ Iterator แต่เป็นสิ่งที่ผู้เขียนเรียกว่า lazy sequences lazy sequences** นั่นเอง