Python Fraction.from_number: รับเฉพาะตัวเลขโดยไม่เผลอ parse ข้อความ
Fraction(value) รับได้ทั้งตัวเลขและ string ซึ่งสะดวกแต่ boundary บางจุดต้องการยืนยันว่า caller ส่ง numeric object จริงครับ Python 3.14 เพิ่ม Fraction.from_number สำหรับ numbers.Rational, float, Decimal และ object ที่มี as_integer_ratio() โดยไม่รับข้อความ
WHY: ช่องรับเหรียญไม่ควรกลายเป็นช่องกรอกคำสั่ง
เหมือนเครื่องที่รับเหรียญหลายชนิดแต่ไม่รับกระดาษเขียนจำนวน แยก parsing จาก calculation ทำให้ validation อ่านง่าย: ชั้น API แปลงข้อความภายใต้นโยบาย locale/format ก่อน แล้วชั้นคำนวณรับเพียงค่าตัวเลข
from decimal import Decimal
from fractions import Fraction
import unittest
class FractionFromNumberTests(unittest.TestCase):
def test_supported_numeric_inputs(self):
self.assertEqual(Fraction.from_number(3), Fraction(3, 1))
self.assertEqual(Fraction.from_number(Decimal("0.25")), Fraction(1, 4))
self.assertEqual(
Fraction.from_number(0.5),
Fraction(1, 2),
)
def test_text_is_not_a_number_boundary(self):
with self.assertRaises(TypeError):
Fraction.from_number("1/4")
def test_binary_float_is_preserved_exactly(self):
value = Fraction.from_number(0.1)
self.assertNotEqual(value, Fraction(1, 10))
self.assertEqual(value.limit_denominator(10), Fraction(1, 10))
if __name__ == "__main__":
unittest.main()
Exact ไม่ได้แปลว่าตรงกับเลขที่มนุษย์พิมพ์
from_number(0.1) เก็บค่าของ binary float ที่มีอยู่จริง จึงได้เศษส่วนยาว ไม่ใช่ 1/10 หาก input มาจากเงินหรือข้อความทศนิยม ใช้ Decimal จาก string ที่ validate แล้ว หรือ parse Fraction ภายใต้ grammar ที่กำหนด อย่าแปลงผ่าน float โดยไม่ตั้งใจ
limit_denominator เป็นการประมาณ ต้องเลือก denominator สูงสุดตามโดเมน เช่น หน่วยวัดหรือเฟรมเรต ไม่ใช้เพื่อ “ซ่อม” ค่าเงินแบบเดา ๆ
Recap
- ใช้
from_numberเมื่อ API ต้องรับ numeric object เท่านั้น - แยก text parsing ออกจาก calculation
- จำว่า float ถูกแปลงแบบ exact ตาม binary value
- ใช้
Decimalหรือ grammar เฉพาะโดเมนเมื่อรับข้อความทศนิยม