Generators และ yield
Generator มีทั้งสองภาษา แต่ Python พึ่งพาหนักกว่ามาก
หัวข้อที่มีชื่อว่า “Generator มีทั้งสองภาษา แต่ Python พึ่งพาหนักกว่ามาก”TypeScript ก็มี generator เหมือนกัน function* คู่กับ yield ทำงานคล้ายกันมากเมื่อมองผ่าน ๆ คือได้ lazy iterator เรียก .next() ได้ และ function หยุดค้างไว้ระหว่าง yield
แต่ใน Python generator ไม่ใช่ฟีเจอร์เฉพาะกลุ่ม เพราะฝังอยู่ทั่ว standard library ทั้ง range(), การวนอ่านไฟล์, zip(), map(), filter() และ module itertools ล้วนคืน lazy iterator ที่ยืนอยู่บน generator protocol ตัวเดียวกัน แม้แต่ async/await ก็สร้างทับ generator อยู่ข้างใน เข้าใจ generator ของ Python ได้ ก็เท่ากับเข้าใจแกนสำคัญของภาษาไปแล้วครึ่งหนึ่ง
การสร้างและใช้งาน generator
หัวข้อที่มีชื่อว่า “การสร้างและใช้งาน generator”generator ของ Python คือ function ใดก็ตามที่มีคำสั่ง yield อยู่ การเรียก function นั้นจะคืนค่า generator object — โค้ดจะยังไม่ทำงานจนกว่าคุณจะวนซ้ำ
// TypeScript generator with function*function* countUp(start: number, stop: number): Generator<number> { let current = start; while (current <= stop) { yield current; current++; }}
const gen = countUp(1, 5);for (const val of gen) { process.stdout.write(val + " ");}console.log();
// Infinite generatorfunction* fibonacci(): Generator<number> { let [a, b] = [0, 1]; while (true) { yield a; [a, b] = [b, a + b]; }}
const fib = fibonacci();const firstTen = Array.from({ length: 10 }, () => fib.next().value);console.log(firstTen);# Python generator with def + yielddef count_up(start, stop): current = start while current <= stop: yield current current += 1
gen = count_up(1, 5)for val in gen: print(val, end=" ")print()
# Infinite generatordef fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b
fib = fibonacci()first_ten = [next(fib) for _ in range(10)]print(first_ten)ข้อแตกต่างสำคัญที่ควรสังเกต:
- Python ใช้
defธรรมดา ไม่มี syntax แบบfunction*ขอแค่มีyieldโผล่ที่ไหนสักแห่งใน function body function นั้นก็กลายเป็น generator ทันที - ลูป
forของ Python ทำงานได้โดยตรงกับ iterable ทุกชนิด รวมถึง generator โดยไม่ต้องเรียก.next()เอง - TypeScript ต้องระบุ return type เป็น
Generator<T>แต่ Python จะอนุมานให้โดยอัตโนมัติ
การสื่อสารสองทางด้วย send()
หัวข้อที่มีชื่อว่า “การสื่อสารสองทางด้วย send()”generator ของ Python รองรับการส่งข้อมูลสองทาง คุณสามารถส่งค่ากลับเข้าไปใน generator ที่หยุดอยู่โดยใช้ .send() ค่าที่ส่งไปจะกลายเป็นผลลัพธ์ของ expression yield ภายใน generator TypeScript รองรับสิ่งนี้ผ่าน gen.next(value) แต่ฟีเจอร์นี้ไม่ค่อยถูกใช้ใน ecosystem ของ TS
// TypeScript: sending values into a generatorfunction* accumulator(): Generator<number, void, number> { let total = 0; while (true) { const value = yield total; if (value === undefined) break; total += value; }}
const acc = accumulator();acc.next(); // prime the generatorconsole.log(acc.next(10).value); // 10console.log(acc.next(20).value); // 30console.log(acc.next(5).value); // 35# Python: sending values into a generator with .send()def accumulator(): total = 0 while True: value = yield total if value is None: break total += value
acc = accumulator()next(acc) # prime the generator (advance to first yield)print(acc.send(10)) # 10print(acc.send(20)) # 30print(acc.send(5)) # 35ลองด้วยตัวเอง
หัวข้อที่มีชื่อว่า “ลองด้วยตัวเอง”def count_up(start, stop): current = start while current <= stop: yield current current += 1
gen = count_up(1, 5)for val in gen: print(val, end=" ")print()
def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b
fib = fibonacci()first_ten = [next(fib) for _ in range(10)]print(first_ten)Loading Python runtime (first run only)…