[Python] Resolving Cyclic Import in Custom Type System for Expression Evaluator

Discussão em 'Python' iniciado por Stack, Março 22, 2025.

  1. Stack

    Stack Membro Participativo

    I'm building a custom expression evaluator that handles operations like max(date_1, date_2) + 90 using type-specific classes. The initial implementation worked when all classes were in a single file, but splitting them into separate modules caused cyclic imports.

    Working Single-File Version

    # Custom Data Type Definitions
    # evaluator.py (original)
    from datetime import date, timedelta

    class DateValue:
    def __init__(self, value: date):
    self.value = value

    def __add__(self, other):
    if isinstance(other, IntValue): # References IntValue
    return DateValue(self.value + timedelta(days=other.value))
    # ... other cases ...

    class IntValue:
    def __init__(self, value: int):
    self.value = value

    def __add__(self, other):
    if isinstance(other, DateValue): # References DateValue
    return DateValue(other.value + timedelta(days=self.value))
    # ... other cases ...


    Problem When Modularizing

    # int_value.py
    from date_value import DateValue # <-- Cyclic import

    class IntValue:
    def __add__(self, other):
    if isinstance(other, DateValue): # Requires DateValue
    # ... implementation ...

    # date_value.py
    from int_value import IntValue # <-- Cyclic import

    class DateValue:
    def __add__(self, other):
    if isinstance(other, IntValue): # Requires IntValue
    # ... implementation ...


    Constraints


    1. Need to maintain strong type checking (isinstance)


    2. Want to avoid local imports inside add methods like:

    def __add__(self, other):
    from date_value import DateValue # **Not desired**



    Attempted Solutions


    1. Using interface/base classes didn't resolve the circular dependency


    2. Tried from future import annotations with string type hints, but runtime isinstance checks still require concrete classes

    Questions

    How can I structure these interdependent classes across modules while avoiding:


    • Cyclic imports


    • Local imports inside operator methods


    • Sacrificing type safety checks?

    Are there established patterns for cross-dependent type systems in Python that handle this scenario cleanly?

    Continue reading...

Compartilhe esta Página