January 15, 2012

Python: เขียนตัวก่อกำเนิดขั้นสูง

โดยปรกติแล้ว ในฟังก์ชันหนึ่งๆ จะจบการทำงานทันทีที่เจอ return ตัวแรก นั่นคือการคืนค่าเพียง 1 เดียวของมัน

โดยถ้าเราไม่ต้องการให้ฟังก์ชันของเราจบการทำงานทันที แต่ก็ยังต้องการผลลัพท์ระหว่างการทำงานเป็นรอบๆ ออกมาเรื่อยๆ นี่คือแนวคิดของ generator นั่นเอง ซึ่งสามารถสร้างได้ง่ายๆ โดยการเปลี่ยน keyword จาก return เป็น yield เช่นตัวอย่างนี้



ในการใช้งาน generator นั้น ปรกติเราจะเรียกมันผ่าน iterator ทั้งหลายอยู่แล้ว เช่น

แต่ถ้าต้องการเรียก generator เป็น object ตรงๆ เพื่อควบคุมการดึงค่าออกมาให้ได้มากขึ้น ก็สามารถทำได้โดย



ข้อดีของมันเหนือการสร้างฟังก์ชันที่วิ่งวนหาค่าที่ต้องการทุกตัวแล้วส่งคืนมาเป็น list คือ generator จะทำงานเท่าที่ร้องขอเท่านั้น lazy evaluation ในรอบการทำงานหนึ่งๆ เมื่อเจอ keyword yield ก็จะหยุดพัก จนกว่าจะถูกเรียกอีกโดย __next__() มันถึงจะวิ่งไปหา yield ตัวถัดไป ทำให้ประหยัดหน่วยความจำมากกว่าการเตรียมทุกค่าไว้ก่อน แถมยังประหยัดเวลาอีกด้วยในกรณีที่มีการ break ออกจาก iterator

และจะยิ่งเห็นข้อดีเด่นชัดขึ้นอีกอย่าง เมื่อเราสามารถนิยาม generator ให้อยู่ในรูปของ iterator ได้ เช่นจากตัวอย่างข้างบน เขียนใหม่สำหรับกรณีทั่วไปได้ดังนี้
ข้อเสียของมันคงเป็นการที่ไม่สามารถระบุตำแหน่งของข้อมูลได้ เช่นตามตัวอย่างนี้ เราไม่สามารถบอกได้ว่าจำนวนเฉพาะตัวที่ 15 คืออะไร จนกว่าเราจะแปลง generator ไปอยู่ในรูปของข้อมูลแบบอื่นๆ อย่างเช่น list ครับ

No comments:

Post a Comment