Python operator.call: ส่งฟังก์ชันเข้า pipeline แบบไม่ต้องห่อ lambda
บาง pipeline เก็บ “งานที่จะเรียกทีหลัง” เป็นรายการ callable แล้วต้องแปลงทุกงานเป็นผลลัพธ์ เรามักเขียน map(lambda fn: fn(), jobs) ทั้งที่ lambda ไม่ได้เพิ่มความหมาย operator.call เป็นฟังก์ชันที่รับ callable แล้วเรียกด้วย arguments ที่ตามมา จึงใช้กับ map หรือ higher-order API ได้ตรง ๆ
from __future__ import annotations
from operator import call
import unittest
def collect(jobs: list[callable]) -> list[str]:
return list(map(call, jobs))
class OperatorCallTests(unittest.TestCase):
def test_calls_each_zero_argument_job(self):
jobs = [lambda: "health", lambda: "metrics", lambda: "ready"]
self.assertEqual(collect(jobs), ["health", "metrics", "ready"])
def test_arguments_can_be_passed_directly(self):
self.assertEqual(call(pow, 2, 5), 32)
if __name__ == "__main__":
unittest.main()
มองมันเหมือนบัตรคำสั่ง “กดปุ่มนี้” ที่ส่งเป็นวัตถุได้ ไม่ต้องสร้างซอง lambda ใหม่ทุกใบ แต่ความสั้นไม่ควรชนะความอ่านง่าย: loop ปกติดีกว่าเมื่อแต่ละงานต้องมี timeout, logging, error policy หรือ argument ต่างกัน
callable ยังอาจมี side effect หรือโยน exception และ map ประเมินแบบ lazy งานจะยังไม่รันจนมีคน consume iterator ตัวอย่างใช้ list เพื่อทำให้จังหวะรันชัด หากต้องการหยุด/ทำต่อเมื่อ error ต้องเขียน control flow ให้เห็นแทนการซ่อนใน pipeline
Recap
- ใช้แทน
lambda fn: fn()ใน pipeline ที่เรียบง่าย - จำว่า
maplazy จนกว่าจะถูก consume - ใช้ loop เมื่อแต่ละงานมี policy ต่างกัน
- อย่าเรียก callable ที่มาจาก input ที่ไม่เชื่อถือ