Python inspect.getmembers_static: สำรวจ object โดยไม่เผลอเรียก property
เครื่องมือสำรวจ object อาจเผลอรัน property, descriptor หรือ __getattr__ แค่เพราะต้องการรายชื่อสมาชิกครับ inspect.getmembers_static หลีกเลี่ยง dynamic lookup จึงเหมาะกับ debugger, linter และ security tooling ที่ไม่ควรเปลี่ยน state ของสิ่งที่กำลังตรวจ
import inspect
import unittest
class Meter:
def __init__(self):
self.reads = 0
@property
def secret(self):
self.reads += 1
return "value"
class InspectTests(unittest.TestCase):
def test_static_inspection_does_not_execute_property(self):
meter = Meter()
members = dict(inspect.getmembers_static(meter))
self.assertIsInstance(members["secret"], property)
self.assertEqual(meter.reads, 0)
dynamic = dict(inspect.getmembers(meter))
self.assertEqual(dynamic["secret"], "value")
self.assertEqual(meter.reads, 1)
if __name__ == "__main__":
unittest.main()
Static ไม่ได้แปลว่าครบเหมือน runtime
วิธี static อาจคืน descriptor object แทนค่าที่ผู้ใช้เห็น และอาจเห็นสมาชิกบางแบบไม่เหมือน dynamic lookup นี่เป็น feature ไม่ใช่ bug เลือก API ตามคำถาม: ต้องการโครงสร้างที่ประกาศไว้ หรือค่าหลัง Python เรียก protocol แล้ว
เหมือนตรวจแผงไฟจากแบบวงจรแทนการกดทุกสวิตช์ เราปลอดภัยกว่า แต่ยังไม่ได้พิสูจน์ว่าอุปกรณ์ปลายทางทำงานจริง
Recap
- ใช้ static inspection เมื่อ side effect ยอมรับไม่ได้
- คาดว่า descriptor จะยังไม่ถูก bind
- อย่าอ้างว่ารายการ static เท่ากับ runtime view ทุกกรณี
- ทดสอบกับ metaclass/descriptor ของระบบจริงก่อนทำ tooling