Python inspect.signature: ตรวจรูปแบบ callable โดยไม่เรียกโค้ดจริง
ระบบ plugin มักอยากรู้ว่า callable รับ context หรือ keyword-only option ได้ไหม การลองเรียกแล้วจับ TypeError เสี่ยงสับสนกับ TypeError ที่เกิดภายในฟังก์ชัน inspect.signature อ่านสัญญาการเรียกโดยไม่ execute body จึงแยก capability check ออกจากงานจริงได้ครับ
WHY: ตรวจปลั๊กก่อนจ่ายไฟ
เหมือนดูรูปทรงปลั๊กกับแรงดันบนฉลากก่อนเสียบ เราตรวจช่องรับ argument โดยไม่เปิดเครื่อง ลด side effect และทำ error ตอนโหลด plugin ให้เข้าใจง่ายกว่า error กลาง request
import inspect
import unittest
from collections.abc import Callable
def accepts_keyword(fn: Callable[..., object], name: str) -> bool:
params = inspect.signature(fn).parameters
if name in params:
return params[name].kind in {
inspect.Parameter.POSITIONAL_OR_KEYWORD,
inspect.Parameter.KEYWORD_ONLY,
}
return any(p.kind is inspect.Parameter.VAR_KEYWORD for p in params.values())
class SignatureTests(unittest.TestCase):
def test_keyword_only_and_kwargs(self) -> None:
def explicit(value: str, *, context: dict[str, str]) -> str:
return value
def flexible(value: str, **kwargs: object) -> str:
return value
def positional_only(context: object, /) -> object:
return context
self.assertTrue(accepts_keyword(explicit, "context"))
self.assertTrue(accepts_keyword(flexible, "context"))
self.assertFalse(accepts_keyword(positional_only, "context"))
if __name__ == "__main__":
unittest.main()
HOW: ดู kind ไม่ใช่ดูแค่ชื่อ
parameter ชื่อเดียวกันอาจเป็น positional-only จึงส่งด้วย keyword ไม่ได้ ตัวอย่างตรวจ POSITIONAL_OR_KEYWORD, KEYWORD_ONLY และ fallback **kwargs แยกกัน ส่วน default และ annotation เป็น metadata ไม่ใช่ validation ที่เชื่อถือได้เสมอ
callable บางชนิดจาก extension หรือ object ที่ตั้ง __signature__ อาจไม่มี signature ที่อ่านได้และโยน TypeError/ValueError ต้องกำหนดนโยบาย fail closed สำหรับ plugin contract สำคัญ อย่า import โมดูลไม่น่าเชื่อถือเพียงเพื่อ inspect เพราะ import เองรัน top-level code ได้ ควรตรวจ provenance และโหลดใน isolation ก่อน
Recap
- inspect ก่อน invoke เพื่อไม่ปน error ภายในกับ signature mismatch
- ตรวจ parameter kind ไม่ใช่ชื่ออย่างเดียว
- กำหนด fallback เมื่อ signature อ่านไม่ได้
- อย่าถือว่า annotation คือ runtime validation
- การ inspect ไม่ทำให้การ import plugin ปลอดภัย