ตัววนซ้ำ (Iterators) ในภาษาไพธอน
บทความนี้อธิบายเกี่ยวกับตัววนซ้ำในไพธอน
YouTube Video
ตัววนซ้ำ (Iterators) ในภาษาไพธอน
ภาพรวม
ในไพธอน ตัววนซ้ำ (iterator) เป็นกลไกพื้นฐานสำหรับประมวลผลสมาชิกของคอลเลกชันเช่น list, tuple และ dictionary ทีละตัว
ตัววนซ้ำ (Iterator) คืออะไร?
ตัววนซ้ำคือ วัตถุที่สามารถคืนค่าสมาชิกทีละตัวได้ ในไพธอน วัตถุจะถือว่าเป็นตัววนซ้ำถ้ามีเงื่อนไขต่อไปนี้ครบสองข้อ:
- มีเมธอด
__iter__()
ซึ่งคืนค่าตัวเอง - มีเมธอด
__next__()
ซึ่งคืนค่าสมาชิกถัดไป เมื่อไม่มีข้อมูลจะคืนค่าอีก จะส่งข้อผิดพลาดStopIteration
1iterator = iter([1, 2, 3])
2print(next(iterator)) # 1
3print(next(iterator)) # 2
4print(next(iterator)) # 3
5# print(next(iterator)) # StopIteration occurs
- ในโค้ดนี้ ฟังก์ชัน
iter()
ถูกใช้ในการแปลงลิสต์ให้เป็นอิเทอเรเตอร์ และฟังก์ชันnext()
ถูกใช้ในการดึงและแสดงแต่ละองค์ประกอบทีละรายการ
ข้อแตกต่างจาก Iterable
อิตเทอราเบิล (Iterable) คือวัตถุที่มีเมธอด __iter__()
และสามารถใช้งานในลูป for
ได้ ลิสต์และทูเพิลเป็นตัวอย่างของอิตเทอราเบิล
1nums = [10, 20, 30]
2it = iter(nums) # Get an iterator from the iterable
3print(next(it)) # 10
- โค้ดนี้เป็นตัวอย่างของการรับอิเทอเรเตอร์จากอิเทอเรเบิล เช่น ลิสต์ และดึงองค์ประกอบตามลำดับโดยใช้
next()
วิธีตรวจสอบ:
1from collections.abc import Iterable, Iterator
2
3nums = [10, 20, 30]
4it = iter(nums)
5
6print(isinstance(nums, Iterable)) # True
7print(isinstance(nums, Iterator)) # False
8print(isinstance(it, Iterator)) # True
- โค้ดนี้ยืนยันว่า
nums
เป็นอิเทอเรเบิลแต่ไม่ใช่อิเทอเรเตอร์ ในขณะที่it
ที่ได้มาจากiter(nums)
เป็นอิเทอเรเตอร์
ความสัมพันธ์ระหว่างลูป for กับตัววนซ้ำ
ลูป for
ในไพธอนทำงานภายในดังนี้:
1nums = [1, 2, 3]
2iterator = iter(nums)
3while True:
4 try:
5 value = next(iterator)
6 print(value)
7 except StopIteration:
8 break
- ดังที่แสดง ลูป
for
ใช้ตัววนซ้ำโดยอัตโนมัติเมื่อวนซ้ำข้อมูล
การสร้างตัววนซ้ำแบบกำหนดเอง
คุณสามารถสร้างตัววนซ้ำแบบกำหนดเองได้โดยใช้คลาส
1class Countdown:
2 def __init__(self, start):
3 self.current = start
4
5 def __iter__(self):
6 return self
7
8 def __next__(self):
9 if self.current <= 0:
10 raise StopIteration
11 value = self.current
12 self.current -= 1
13 return value
14
15for num in Countdown(3):
16 print(num) # 3, 2, 1
- โค้ดนี้กำหนดอิเทอเรเตอร์แบบกำหนดเองที่นับถอยหลังโดยใช้คลาส
Countdown
และพิมพ์ตัวเลขตั้งแต่ 3 ถึง 1 ด้วยลูปfor
ข้อแตกต่างระหว่าง Iterators กับ Generators และสถานการณ์ที่เหมาะสมในการใช้งาน
เจเนอเรเตอร์ (Generator) มีหน้าที่คล้ายกับตัววนซ้ำ สามารถสร้างตัววนซ้ำได้อย่างกระชับและง่ายขึ้น
1def countdown(n):
2 while n > 0:
3 yield n
4 n -= 1
5
6for i in countdown(3):
7 print(i) # 3, 2, 1
- โค้ดนี้กำหนดฟังก์ชันเจเนอเรเตอร์ที่นับถอยหลังโดยใช้
yield
และพิมพ์ตัวเลขตั้งแต่ 3 ถึง 1 ด้วยลูปfor
ความแตกต่างระหว่างตัววนซ้ำ (คลาส) และเจเนอเรเตอร์ (ฟังก์ชัน)
มีความแตกต่างดังต่อไปนี้ระหว่างอิเทอเรเตอร์ (คลาส) และเจเนอเรเตอร์ (ฟังก์ชัน):
คุณสมบัติ | Iterator (คลาส) | Generator (ฟังก์ชัน) |
---|---|---|
การนิยาม | __iter__() + __next__() |
ฟังก์ชันที่ใช้ yield |
การจัดการสถานะ | ต้องจัดการแอตทริบิวต์เอง | จัดการสถานะโดยอัตโนมัติ |
ความอ่านง่าย | อาจซับซ้อน | เรียบง่ายและชัดเจน |
-
ความแตกต่างในการนิยาม ตัววนซ้ำถูกนิยามโดยการเขียนเมธอด
__iter__()
และ__next__()
ด้วยตนเอง ในทางตรงข้าม เจเนอเรเตอร์เป็นเพียงฟังก์ชันที่ใช้คีย์เวิร์ดyield
จึงทำให้โค้ดกระชับและเรียบง่ายกว่า -
ความแตกต่างในการจัดการสถานะ สำหรับตัววนซ้ำ คุณต้องจัดการสถานะและความคืบหน้าด้วยตนเองโดยใช้ตัวแปร แต่เจเนอเรเตอร์จะเก็บสถานะไว้ภายในโดยอัตโนมัติ ลดภาระในการจัดการ
-
ความอ่านง่ายของโค้ด ตัววนซ้ำมักจะซับซ้อนเพราะต้องมีหลายเมธอดและต้องจัดการสถานะเอง ในขณะที่เจเนอเรเตอร์ใช้ไวยากรณ์ง่าย ทำให้เข้าใจได้ง่ายแม้กระทั่งผู้เริ่มต้น
ไลบรารีมาตรฐานสำหรับใช้ตัววนซ้ำ: itertools
itertools
เป็นไลบรารีมาตรฐานของไพธอนที่มีเครื่องมือทรงพลังสำหรับทำงานกับตัววนซ้ำ
1import itertools
2
3for x in itertools.count(10, 2): # 10, 12, 14, ...
4 if x > 20:
5 break
6 print(x)
- มันยังมีฟังก์ชันอื่น ๆ เช่น
cycle
,repeat
,chain
,islice
, และtee
กรณีตัวอย่างการใช้งานตัววนซ้ำ
กรณีการใช้งานของอิเทอเรเตอร์ประกอบด้วยสิ่งต่อไปนี้:
- การอ่านไฟล์ทีละบรรทัด: อ่านข้อมูลทีละบรรทัดจากไฟล์โดยใช้ตัววนซ้ำ
- ประมวลผลข้อมูลด้วยหน่วยความจำอย่างมีประสิทธิภาพ: ประมวลผลข้อมูลปริมาณมากแบบเรียงลำดับทีละรายการ
- สร้างลำดับค่าที่ไม่มีที่สิ้นสุด: ใช้ฟังก์ชันอย่าง
itertools.count()
สรุป
- ตัววนซ้ำคือวัตถุที่สามารถดึงค่าถัดไปทีละค่าได้
- คุณสามารถสร้างตัววนซ้ำที่กำหนดเองได้ด้วยการกำหนด
__iter__()
และ__next__()
- ตัววนซ้ำจะถูกจัดการโดยอัตโนมัติผ่านลูป
for
หรือใช้ฟังก์ชันnext()
- การใช้เจเนอเรเตอร์หรือ
itertools
ช่วยให้ประมวลผลได้อย่างมีประสิทธิภาพมากขึ้น
ด้วยการใช้ตัววนซ้ำ คุณสามารถประมวลผลข้อมูลปริมาณมากทีละรายการอย่างประหยัดหน่วยความจำ จัดการสถานะได้ดีขึ้นและเพิ่มประสิทธิภาพของโปรแกรม
คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย