ตัววนซ้ำ (Iterators) ในภาษาไพธอน

ตัววนซ้ำ (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 ด้วย

YouTube Video