ASHD Dev_Blog

future

이재룡
이재룡 Oct 28, 2025

네, from __future__ import annotations의 목적과 사용 이유에 대해 자세히 설명해 드리겠습니다.

from __future__ import annotations란 무엇인가요?

이 구문은 파이썬 3.7부터 도입된 기능으로, 타입 어노테이션(Type Annotation)의 평가를 지연시키는 역할을 합니다.

일반적으로 파이썬은 코드를 읽어 들일 때 함수나 변수의 타입 힌트를 즉시 평가하여 해당 타입이 실제로 존재하는지 확인합니다. 하지만 from __future__ import annotations를 파일 맨 위에 선언하면, 파이썬은 타입 힌트를 실제 타입으로 평가하는 대신 문자열(string) 형태로 저장해 둡니다.

왜 사용해야 할까요?

이 기능을 사용하는 주된 이유는 두 가지 큰 문제를 해결하기 위함입니다.

1. 순환 참조 (Circular Imports) 문제 해결

두 개의 모듈(파일)이 서로를 임포트해야 하는 상황을 생각해 보겠습니다.

  • a.py는 b.py에 정의된 B 클래스를 타입 힌트로 사용합니다.
  • b.py는 a.py에 정의된 A 클래스를 타입 힌트로 사용합니다.

이 코드를 실행하면 ImportError: cannot import name 'A' from partially initialized module 'a' 와 같은 순환 참조 오류가 발생합니다. a.py가 B를 가져오려고 b.py를 임포트하는 순간, b.py는 다시 A를 가져오려고 a.py를 임포트하는데, 이때 a.py의 class A 정의가 아직 완료되지 않았기 때문입니다.

from __future__ import annotations를 사용하면 이 문제가 해결됩니다.

이제 파이썬이 코드를 읽을 때 b_instance: B에서 B를 실제 클래스로 찾지 않고, 단순히 문자열 "B"로 처리합니다. 따라서 임포트 시점에는 오류가 발생하지 않고, 실제 코드가 실행되거나 타입 체커(mypy 등)가 타입을 검사할 때가 되어서야 이 문자열을 실제 타입으로 해석하게 됩니다.

2. 전방 참조 (Forward References) 문제 해결

클래스 내부의 메서드가 자기 자신 클래스 타입을 반환하거나 인자로 받아야 할 때가 있습니다.

위 코드는 Node 클래스의 정의가 끝나기 전에 Node라는 이름을 타입 힌트로 사용하려고 해서 NameError가 발생합니다.

과거에는 이 문제를 해결하기 위해 타입 힌트를 직접 문자열로 감싸주었습니다.

하지만 from __future__ import annotations를 사용하면 코드가 훨씬 깔끔해집니다.

요약

  • 목적: 타입 힌트의 평가 시점을 코드가 실제로 실행될 때까지 지연시킨다. (Postponed Evaluation of Annotations)
  • 동작: 타입 힌트를 실제 객체가 아닌 문자열로 저장한다.
  • 주요 사용 이유:
      1. 순환 참조: 모듈 간 상호 임포트로 인한 ImportError를 방지합니다.
      1. 전방 참조: 클래스 정의가 완료되기 전에 자기 자신을 타입 힌트로 사용할 수 있게 하여 코드를 깔끔하게 만듭니다.
  • 추가 이점: 타입 힌트를 평가하는 데 드는 시간이 줄어들어 모듈 로딩 속도가 약간 빨라질 수 있습니다.
 
 
 

[ 1. Variable & Constant ]

Variable

  • var <변수명> <type> = <초기값>
  • 타입 추론 <변수명> := <값>
 

Constant

  • iota : 0번 부터 시작하는 상수 열거형 at (enum을 만들 거나 할 때)
 
 

[ 2. Datatype ]

String

  • backQuote(’’)
  • DoubleQuote(’’)에서만 /n 과 같은 문자열 해석이 가능
Callout icon'
go에서는 type conversion 문제가 발생했을 때,
compile error가 아닌 runtime error가 발생 ( 오류 체크 할 때 주의 필요! )
 

Pointer

  • &k - 주소 할당
  • *p - 해당 주소의 실제 내용
 
 

[ 3. Collection ]

Array

  • zero-base 초기화가 자동
  • var <변수명> [크기]<type>

< 응용 : Slice >

  • python처럼 sub slice 이용
  • slice[start idx : end idx +1 ]

< 응용 : append 활용 >

 

Map

  • 기본형 map [key_type] value_type
  • 키 값 확인 key_val, exists := map["value"]
 
 

[ 4. 조건문 / 반복문 ]

if / else if / else

  • ( )는 안 쓰지만 { }는 필수
  • else if/else를 쓸 때는 반드시 전 조건의 마지막 ‘}’ 와 같은 라인에 써준다.
  • 다중 조건 ‘;’ 로 가능
 

for (no while)

  • 반복문에서 while이 없음
  • ( )는 사용하지 않음

< 응용 : range >

  • python처럼 range 사용 가능 (단 index까지 반드시 포함)
  • 기본적으로 break 사용가능

⇒ 즉 index와 리스트에서 뽑은 데이터 총 2개의 값을 for range에서 이용

< 응용 : 중첩 루프 탈출 : break[Label] >

  • label을 이용하여 for문을 건너뛰고 반복문 탈출 가능
  • label은 for문 앞에 선언되며, 여러 개의 for문을 한번에 탈출 가능
 
 

추천 글

BlogPro logo