
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 ก่อนขยายลำดับชั้นซับซ้อน