นากกายจัดหมุดรูปร่างสีต่างๆ ลงถาดไม้บนโต๊ะมิ้นต์

Python StrEnum: ติดป้ายสถานะที่เป็นสตริงโดยไม่ต้อง .value ทุกครั้ง

น้องกายEngineering

เคยส่งสถานะงานเข้า JSON แล้วลืม .value จนได้ object แปลก ๆ ไหม ผมเคย จนย้ายมาใช้ StrEnum

ตามเอกสาร enum คลาส StrEnum ทำให้สมาชิกเป็นทั้ง enum และ str พร้อมกัน เหมาะกับป้ายข้อความคงที่ เช่น สถานะคิว หรือชื่อช่องทาง

เลือกแบบไหน

  • ใช้ Enum ปกติเมื่ออยากกันการเทียบกับสตริงโดยไม่ตั้งใจ
  • ใช้ StrEnum เมื่อค่าต้องไหลไป API / ล็อก / JSON เป็นข้อความบ่อย

อย่าผสมสองสไตล์ในโดเมนเดียวกันโดยไม่มีเหตุผล เพราะทีมจะสับสนว่าต้องเทียบยังไง

import unittest
from enum import Enum, StrEnum


class TicketStatus(Enum):
    OPEN = "open"


class TicketLabel(StrEnum):
    OPEN = "open"
    CLOSED = "closed"


class StrEnumTests(unittest.TestCase):
    def test_plain_enum_not_equal_to_str(self):
        self.assertNotEqual(TicketStatus.OPEN, "open")
        self.assertEqual(TicketStatus.OPEN.value, "open")

    def test_strenum_equals_and_formats(self):
        self.assertEqual(TicketLabel.OPEN, "open")
        self.assertEqual(f"status={TicketLabel.CLOSED}", "status=closed")
        self.assertIsInstance(TicketLabel.OPEN, str)


if __name__ == "__main__":
    unittest.main()

ข้อควรระวัง

StrEnum สะดวก แต่ทำให้ขอบเขตชนิดอ่อนลงในบางจุด ถ้าโดเมนต้องการแยกชนิดเข้มงวด ให้ใช้ Enum แล้ว serialize ชัดเจนที่ขอบเขต และตั้งชื่อสมาชิกให้อ่านเป็นป้ายธุรกิจ ไม่ใช่แค่ตัวเลขลับ ๆ

Recap

  • ใช้ StrEnum เมื่อป้ายคือข้อความที่ต้องเทียบ/ต่อสตริงบ่อย
  • ใช้ Enum เมื่ออยากกันการเทียบสตริงเผลอ ๆ
  • เขียนเทสต์สั้น ๆ กัน regression ตอนรีแฟกเตอร์สถานะ
  • อ่านเอกสาร enum ก่อนขยายลำดับชั้นซับซ้อน