future
네, 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)
- 동작: 타입 힌트를 실제 객체가 아닌 문자열로 저장한다.
- 주요 사용 이유:
- 순환 참조: 모듈 간 상호 임포트로 인한
ImportError를 방지합니다. - 전방 참조: 클래스 정의가 완료되기 전에 자기 자신을 타입 힌트로 사용할 수 있게 하여 코드를 깔끔하게 만듭니다.
- 추가 이점: 타입 힌트를 평가하는 데 드는 시간이 줄어들어 모듈 로딩 속도가 약간 빨라질 수 있습니다.
[ 1. Variable & Constant ]
Variable
- var <변수명> <type> = <초기값>
- 타입 추론 <변수명> := <값>
Constant
- iota : 0번 부터 시작하는 상수 열거형 at (enum을 만들 거나 할 때)
[ 2. Datatype ]
String
- backQuote(’’)
- DoubleQuote(’’)에서만 /n 과 같은 문자열 해석이 가능
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문을 한번에 탈출 가능