Skip to content

Instantly share code, notes, and snippets.

@goabonga
Last active July 24, 2025 09:01
Show Gist options
  • Select an option

  • Save goabonga/4dfbc3aeb8083dce6b7f6bd6242ae244 to your computer and use it in GitHub Desktop.

Select an option

Save goabonga/4dfbc3aeb8083dce6b7f6bd6242ae244 to your computer and use it in GitHub Desktop.
En Python moderne (3.10+), est-il préférable d'utiliser from __future__ import annotations plutôt que if TYPE_CHECKING pour éviter les imports circulaires dans les annotations de type ?

En Python moderne (3.10+), from __future__ import annotations et if TYPE_CHECKING ne s'opposent pas, ils sont complémentaires et souvent utilisés ensemble dans du code idiomatique.

from future import annotations

  • Rend toutes les annotations paresseuses (lazy) en les stockant sous forme de chaînes de caractères, évitant ainsi l'évaluation immédiate des types au moment du parsing du module.
  • Cela évite les imports circulaires dans les annotations uniquement, sans avoir besoin de quotes autour des noms de classes.
  • Utile pour tous les usages d’annotations, même en dehors des blocs conditionnels.

if TYPE_CHECKING

  • Ce bloc permet d’importer des modules ou classes uniquement pour les outils de typage statique (mypy, pyright, etc.), sans exécuter l'import à runtime.
  • Cela permet d’éviter les imports inutiles ou coûteux au runtime, tout en satisfaisant les vérificateurs de type.
  • Nécessaire même avec from __future__ import annotations si tu veux éviter l’import réel d’un module ou d’une classe à l’exécution.

Note : compatibilité avec l’API typing Même avec from __future__ import annotations, certains types issus de typing (ex. Union, Optional, List, etc.) peuvent poser problème dans certains contextes (ex. introspection, get_type_hints, ou runtime validation comme avec Pydantic).

  • Exemple : Optional["MyClass"] fonctionne bien avec from __future__ import annotations, mais attention si MyClass est utilisé directement dans du code d’exécution (ex. isinstance(obj, MyClass)) dans ce cas, l’import réel est requis.
  • Autre point : certains usages dynamiques (ex. analyse via typing.get_args()) nécessitent que les annotations soient des objets, pas des chaînes. Il faudra donc explicitement les évaluer via typing.get_type_hints.

En pratique, on combine souvent les deux :

from __future__ import annotations
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from .manager import WorkflowManager  # pas chargé au runtime

class Workflow:
    def __init__(self, manager: WorkflowManager):  # annotations évaluées paresseusement
        self.manager = manager

Conclusion from __future__ import annotations résout le problème de l’évaluation prématurée des annotations. if TYPE_CHECKING évite l’exécution réelle de l’import pendant l’exécution.

Les deux sont donc idiomatiques et recommandés ensemble dans du code moderne, surtout dans les projets structurés ou modulaires où les imports circulaires sont fréquents.

In modern Python (3.10+), from __future__ import annotations and if TYPE_CHECKING are not mutually exclusive—they are complementary and often used together in idiomatic code.

from future import annotations

  • Makes all annotations lazy by storing them as strings, which prevents the immediate evaluation of types when the module is parsed.
  • This avoids circular imports in annotations only, without requiring quotes around class names.
  • Useful for all annotation use cases, even outside of conditional blocks.

if TYPE_CHECKING

  • This block allows importing modules or classes only for static type checkers (mypy, pyright, etc.) without executing the import at runtime.
  • This helps avoid unnecessary or expensive imports at runtime while still satisfying type checkers.
  • Still necessary even with from future import annotations if you want to prevent actual imports during execution.

Note: compatibility with the typing API Even with from __future__ import annotations, some typing types (e.g., Union, Optional, List, etc.) may still cause issues in certain contexts (e.g., introspection, get_type_hints, or runtime validation with Pydantic).

  • Example: Optional["MyClass"] works fine with from future import annotations, but beware if MyClass is used directly in runtime code (e.g., isinstance(obj, MyClass)), in which case a real import is required.
  • Another point: some dynamic usages (e.g., analysis via typing.get_args()) require annotations to be actual objects, not strings. You’ll need to explicitly evaluate them using typing.get_type_hints.

In practice, we often combine both:

from __future__ import annotations
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from .manager import WorkflowManager  # not imported at runtime

class Workflow:
    def __init__(self, manager: WorkflowManager):  # annotations are lazily evaluated
        self.manager = manager

Conclusion from __future__ import annotations prevents premature evaluation of annotations. if TYPE_CHECKING avoids executing real imports at runtime.

Both are idiomatic and recommended in modern Python code, especially in structured or modular projects where circular imports are common.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment