Python partialmethod: สร้างเมธอดเฉพาะทางโดยยังผูก self ถูกตำแหน่ง
คลาสมักมีเมธอดแกนกลางหนึ่งตัว แล้วมีชื่อสั้นสำหรับชุด argument ที่ใช้บ่อย เช่น enable() และ disable() ซึ่งเรียก set_enabled(True/False) การเขียน wrapper สองตัวไม่ผิด แต่เพิ่มจุดที่ documentation และ behavior อาจหลุดจากกัน functools.partialmethod สร้าง descriptor ที่ตรึง argument บางส่วนไว้และยังผูก self ตอนเรียกผ่าน instance ครับ
import unittest
from functools import partialmethod
class FeatureFlag:
def __init__(self) -> None:
self.enabled = False
self.reason = "initial"
def set_state(self, enabled: bool, *, reason: str) -> None:
self.enabled = enabled
self.reason = reason
enable = partialmethod(set_state, True)
disable = partialmethod(set_state, False)
class PartialMethodTests(unittest.TestCase):
def test_binds_instance_before_fixed_argument(self):
flag = FeatureFlag()
flag.enable(reason="rollout")
self.assertTrue(flag.enabled)
self.assertEqual(flag.reason, "rollout")
flag.disable(reason="incident")
self.assertFalse(flag.enabled)
self.assertEqual(flag.reason, "incident")
if __name__ == "__main__":
unittest.main()
ทำไมไม่ใช้ partial ตรง ๆ
partial เป็น callable ทั่วไปและไม่จัดการ descriptor binding แบบเมธอดตามที่เราต้องการ ถ้านำไปวางเป็น class attribute การสอด self อาจไม่เกิดในตำแหน่งที่คาด partialmethod ถูกออกแบบมาสำหรับกรณีนี้โดยเฉพาะ: เมื่อ callable ต้นทางเป็น descriptor มันจะ delegate __get__; ถ้าไม่ใช่ มันจะสร้าง bound method แล้วเติม instance ก่อน argument ที่ตรึงไว้
ใช้เทคนิคนี้เมื่อเมธอดย่อยมีความหมายเป็นชื่อทางโดเมนจริง ไม่ใช่เพื่อซ่อน argument จำนวนมาก ถ้าแต่ละทางต้อง validation, permission หรือ side effect ต่างกัน wrapper ปกติจะอ่านและ debug ง่ายกว่า นอกจากนี้เครื่องมือ introspection หรือ documentation บางตัวอาจแสดง signature ที่ไม่ชัดเท่าเมธอดประกาศตรง ควรตรวจเอกสารที่ generate จริงก่อนใช้ใน public API
เทสต์ควรเรียกผ่าน instance อย่างน้อยหนึ่งครั้งเพื่อจับ binding ผิด และทดสอบ keyword-only argument ที่ยังเปิดให้ผู้เรียกกำหนด อย่าตรึง mutable object แล้วแก้ร่วมกันข้าม instance เพราะค่าที่ตรึงอยู่กับ descriptor ระดับ class
Recap
- ใช้
partialmethodกับ shortcut ที่ตรึง argument ของ instance method - มันผูก
selfต่างจากpartialที่เป็น callable ทั่วไป - ใช้ wrapper ปกติเมื่อ behavior ของแต่ละชื่อแตกต่างจริง
- ตรวจ signature/docs และหลีกเลี่ยง mutable argument ร่วมครับ