วิธีสร้าง Python Iterator: คู่มือ
Iterators (อิเทอเรเตอร์) อยู่ทุกที่ใน Python ยากที่จะเรียนรู้พื้นฐานโดยไม่ได้ยินคำว่า "iterator" หรือ "iterable"
Iterator คือออบเจ็กต์ที่สามารถวนซ้ำได้ แม้จะมีออบเจ็กต์ในตัวบางอย่างที่สามารถวนซ้ำได้ คุณยังสามารถกำหนดเองได้อีกด้วย
ในคู่มือนี้ เราจะพูดถึง Python Iterators ว่าทำงานอย่างไร และวิธีใช้ในโค้ดของคุณ เราจะสร้าง Iterator ของเราเองเพื่อให้คุณเรียนรู้คุณสมบัติหลักในการทำงาน โค้ดในคู่มือนี้รองรับ Python 3.x
มาเริ่มกันเลย!
Iterator คืออะไร?
Iterators คือออบเจ็กต์ที่คุณสามารถวนซ้ำได้ Iterator จะคืนค่าข้อมูลจากออบเจ็กต์นั้น ทีละรายการ
คุณสามารถตรวจสอบว่าออบเจ็กต์เป็น iterable ได้โดยลองรันมันผ่านลูป for หากคุณวนลูปผ่านออบเจ็กต์ได้ แสดงว่ามันเป็น iterable สตริง ลิสต์ ทูเพิล และ Dictionary เป็นตัวอย่างของชนิดข้อมูลในตัวที่เป็น iterable objects
ออบเจ็กต์ Iterator ใน Python ต้องมีสองเมธอด:
__iter__(): ช่วยให้คุณดึง Iterator ได้__next__(): ช่วยให้คุณได้ค่าถัดไปใน Iterator
Underscore (__) ถูกใช้ใน Iterators เพราะแสดงถึงฟังก์ชันพิเศษ ในการกำหนด Iterator คุณต้องใช้ฟังก์ชันพิเศษสองตัวนี้ ร่วมกันเรียกว่า Iterator Protocol เมธอดเหล่านี้มักอ่านว่า "iter and next methods"
วิธีสร้าง Infinite Iterator
เราจะเริ่มจากพื้นฐาน: การสร้าง Infinite Iterator นี่คือประเภท Iterator ที่เรียบง่ายที่สุด มันเรียบง่ายจนจะทำงานต่อไปเรื่อยๆ เราจะแก้ไขในภายหลังของบทช่วยสอน
มาเริ่มด้วยการกำหนดคลาสชื่อ Cakes ซึ่งจะเป็นคลาส Iterator ของเรา:
class Cakes:
def __init__(self, value):
self.value = value
เราประกาศเมธอด __init__ ซึ่งจะถูกดำเนินการทันทีที่ออบเจ็กต์ของคลาสของเราถูกสร้างขึ้น (instantiated) เมธอด __init__ เรียกว่า Constructor (คอนสตรัคเตอร์) ในตัวอย่างนี้ __init__ ของเราสามารถรับค่าได้หนึ่งค่า: value
ต่อไป เราจะสร้าง Iterator Protocol ของเรา:
def __iter__(self):
return self
def __next__(self):
return self.value
เมธอด __iter__ ใช้เพื่อดึงออบเจ็กต์ Iterator ของเรา เมธอด __next__ ช่วยให้เราดึงค่าถัดไปในออบเจ็กต์ที่วนซ้ำได้ที่เราระบุ
มาตรวจสอบว่าโค้ดของเราทำงานจนถึงตอนนี้ เราจะทำโดยการกำหนดออบเจ็กต์ของคลาสของเราแบบนี้:
cake = Cakes(["Vanilla Sponge"])
จนตอนนี้ดีแล้ว! คุณอาจคิดว่า: ทำไมโค้ดนี้ไม่ทำอะไรเลย? เพราะคลาสของเราแค่คืนค่าฟังก์ชัน Iterator
เราต้องวนซ้ำผ่าน Iterator ของเราเพื่อตรวจสอบว่ามันทำงาน เราสามารถทำได้โดยใช้ลูป for-in:
for c in cake:
print(c)
โค้ดของเราคืนค่า:
Vanilla Sponge Vanilla Sponge …
คำสาปของ Vanilla Sponge! มันพิมพ์ออกคอนโซลไปเรื่อยๆ อะไรเกิดขึ้น? เราเพิ่งสร้าง Iterator แรกของเรา มันเรียบง่ายมาก แต่มันทำงาน
การทดสอบ Iterators โดยใช้ลูป for-in ใน Python
ก่อนที่เราจะทำให้ Iterator ของเรามีประโยชน์ มาใช้เวลาทบทวนแนวคิดของลูป for-in ในตัวอย่างล่าสุด เราเขียนลูป for-in เพื่อทดสอบโค้ดของเรา:
for c in cake:
print(c)
วิธีที่ลูป for-in ทำงานคือ มันสร้าง Iterator ของออบเจ็กต์ก่อนโดยใช้เมธอด __iter__() ลูป for-in จะเรียก __next__() จนกว่าจะไม่มีค่าคืน
คุณสามารถคิดถึงลูป for-in ว่าเป็นลูป while แบบง่ายๆ ขณะที่ยังมีค่าที่ Iterator สามารถคืนค่าได้ ลูป for-in จะคืนค่าเหล่านั้น
การสร้าง Iterator ที่มีประโยชน์
Iterator ล่าสุดของเราไม่ค่อยมีประโยชน์ มันพิมพ์ค่าเดียวกันซ้ำๆ แต่ก็ยังเป็น Iterator: มันสามารถอ่านออบเจ็กต์ทั้งหมดใน iterable ได้
เราจะสร้าง Iterator ที่วนซ้ำผ่านอาร์เรย์ Python อาร์เรย์นี้มีลิสต์ของเค้ก
เพื่อหยุด Iterator ไม่ให้ทำซ้ำไปเรื่อยๆ เราจะติดตามว่ามีค่ากี่ค่าภายใน iterable ของเรา และ Iterator ของเราทำงานไปกี่ครั้ง นี่จะช่วยให้เราหยุด Iterator ไม่ให้ทำงานต่อเมื่อมันวนผ่านทุกรายการใน iterable แล้ว
เปิดไฟล์ Python ใหม่และวางโค้ดต่อไปนี้:
class Cakes:
def __init__(self, value):
self.value = value
self.max = len(value)
self.count = 0
def __iter__(self):
return self
def __next__(self):
if self.count < self.max:
to_return = self.value[self.count]
self.count += 1
return to_return
else:
raise StopIteration
Iterator นี้ซับซ้อนกว่าตัวก่อนหน้านิดหน่อย นั่นคือเหตุผลที่เราสร้าง Infinite Iterator ก่อน ใน Iterator นี้ เราเริ่มต้นค่า 3 ค่า:
- value: รายการที่เราต้องการวนซ้ำ
- max: จำนวนรายการใน iterable ของเรา
- count: จำนวนครั้งที่ Iterator ของเราทำงาน
ในเมธอด __next__() เราเพิ่มคำสั่ง "if" คำสั่งนี้ตรวจสอบว่าจำนวนครั้งที่ Iterator ของเราทำงาน (count) น้อยกว่าจำนวนรายการที่ iterable ของเราควรวนซ้ำ (max) หรือไม่
ถ้า "count" น้อยกว่า "max" Iterator ของเราจะหาค่าถัดไปในออบเจ็กต์ iterable มันจะเพิ่ม 1 ให้ตัวแปร "count" ของเรา เพื่อให้เราติดตามได้ว่ายังเหลือออบเจ็กต์กี่ชิ้นที่ต้องวนซ้ำ จากนั้นเราคืนค่าที่เราคำนวณ
สำคัญที่ต้องสังเกตว่า เรากำหนดค่าให้ตัวแปร "to_return" ก่อน ที่จะเพิ่มตัวแปร "count" นี่ทำให้เราสามารถเข้าถึงค่าในรอบการวนซ้ำปัจจุบันของ Iterator ได้
หากเราวนซ้ำผ่านทุกรายการในลิสต์แล้ว Exception จะถูก raise ชื่อ StopIteration นี่จะหยุดโปรแกรมของเราทันทีที่เราวนผ่านทุกรายการในลิสต์
มาดูว่า Iterator ของเราทำงานหรือไม่ เพิ่มโค้ดต่อไปนี้ในโปรแกรมหลักและรันมัน:
cake = Cakes(["Vanilla Sponge"])
for c in cake:
print(c)
โค้ดของเราคืนค่า:
Vanilla Sponge
มาเพิ่มรายการอีกนิดหน่อยในลิสต์และดูว่าจะเกิดอะไรขึ้น:
cake = Cakes(["Vanilla Sponge", "Carrot", "Coffee"])
for c in cake:
print(c)
โค้ดของเราคืนค่า:
Vanilla Sponge Carrot Coffee
เราทำได้แล้ว! เราสร้าง Iterator ที่วนลูปผ่านลิสต์เค้กของเราสำเร็จ คุณสมควรได้เค้ก - หรือถึงแค่คัพเค้ก - สำหรับการมาถึงจุดนี้
สรุป
Iterators ช่วยให้คุณสร้างออบเจ็กต์ที่สามารถวนซ้ำได้ Iterator สามารถวนลูปผ่านลิสต์ สตริง หรือออบเจ็กต์ iterable อื่น และดำเนินการเฉพาะเจาะจง
คุณพร้อมสำหรับความท้าทายไหม? สร้าง Iterator ที่วนลูปผ่านลิสต์ตัวเลขและคืนค่าแต่ละตัวคูณสอง
โค้ดสำหรับ Iterator นี้จะคล้ายกับตัวอย่างข้างต้น - จะยังใช้ Iterator Protocol - แต่ควรคูณตัวเลขแต่ละตัวในลิสต์ด้วยสองก่อนคืนค่าไปยังโปรแกรมหลัก
ตอนนี้คุณพร้อมที่จะเริ่มเขียน Iterator ของคุณเองใน Python อย่างมืออาชีพแล้ว!