함수 정의에서 순환참조가 발생할 경우, 내부 import를 통해 해결한다. 그러나 함수 외부에 작성하는 return type hint는 내부 import의 유효 범위를 벗어나기에 내부 import 선언만으로 해결할 수 없다.

return type hint에 활용하기 위한 import는 런타임에 필요하지 않으므로 아래 조건문을 섞은 모듈 import와 return type hint를 string으로 작성하는 Forward reference 방식을 사용한다. 다만, forword reference는 Python 3.10부터 제공하는 |을 통한 Union 대체가 적용되지 않는다.

문제 상황

from models import Foo  # Error: 순환참조 발생!

def my_function(created: bool) -> Foo | None:
    from models import Foo  # return type hint에는 적용 안됨

    return Foo() if created else None

해결책

from typing import Optional
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from models import Foo  # 런타임에는 실행되지 않음

def my_function(num: int) -> Optional['Foo']:
    from models import Foo  # return type hint에는 적용 안됨

    return Foo() if created else None

개선

future.annotations를 불러와 string type hint 작성을 피할 수 있다. (PEP 563 참고)

Python 3.11부터는 자동으로 선언되므로 import를 생략할 수 있다.

from __future__ import annotations  # Python 3.11 이상에서 생략 가능

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from models import Foo  # 런타임에는 실행되지 않음

def my_function(num: int) -> Foo | None:
    from models import Foo  # return type hint에는 적용 안됨

    return Foo() if created else None