파이썬은 동적 타이핑(dynamic typing) 언어로 잘 알려져 있습니다. 이는 변수의 타입을 명시할 필요 없이 모든 값이 실행 시간에 체크되는 것을 의미합니다. 그러나 대규모 프로젝트가 복잡해지고 여러 개발자가 협력하게 되면서, 코드의 이해 및 유지보수가 어려워질 수 있습니다. 이를 해결하기 위해 파이썬 3.5부터는 타입 어노테이션(Type Annotation)이 도입되었습니다. 타입 어노테이션을 사용하면 코드의 가독성을 높이고 버그를 예방하며 자동 완성 기능을 향상시키는 데 도움이 됩니다.
1. 타입 어노테이션의 기초
타입 어노테이션은 변수나 함수의 타입을 명시적으로 기술할 수 있게 해주는 문법입니다. 다음은 변수와 함수의 타입을 어노테이션하는 기본적인 방법입니다:
변수 어노테이션:
x: int = 10
y: float = 10.5
name: str = "Alice"
함수 어노테이션:
def greeting(name: str) -> str:
return "Hello " + name
1.1 변수의 타입 어노테이션
변수의 타입을 지정하여 코드 작성자는 특정한 타입이 기대된다는 의도를 명확히 할 수 있습니다. 이는 툴링과 IDE에서 정적 분석을 통해 오류를 사전에 감지할 수 있게 해줍니다.
1.2 함수의 파라미터와 반환 값 어노테이션
함수 어노테이션을 통해 함수의 입력과 출력 타입을 명시할 수 있으며, 함수가 어떠한 타입의 데이터를 받을지 예상할 수 있도록 도와줍니다. 이는 코드 리뷰 시 큰 도움이 됩니다.
2. 내장 데이터 타입
파이썬은 다양한 내장 데이터 타입을 지원하며, 이 타입들을 어노테이션에 사용할 수 있습니다.
- Int, float, str, bool, None 등 기본 타입
- List, Dict, Set, Tuple 등 컨테이너 타입은 typing 모듈을 통해 더 세분화할 수 있습니다.
from typing import List, Dict, Tuple
names: List[str] = ["Alice", "Bob", "Charlie"]
scores: Dict[str, int] = {"Alice": 95, "Bob": 85}
position: Tuple[int, int] = (10, 20)
3. 유니언과 옵셔널
여러 타입을 허용해야 하는 경우 Union
을 사용하고, None을 허용하는 경우 Optional
을 사용하는 것이 일반적입니다.
from typing import Union, Optional
value: Union[int, float] = 5.5
def get_user(id: int) -> Optional[Dict[str, str]]:
if id == 1:
return {"name": "Alice", "role": "admin"}
return None
4. 사용자 정의 타입
복잡한 타입을 정의해야 하는 경우, Type
또는 NewType
을 사용하여 더욱 명확한 코드를 작성할 수 있습니다.
from typing import NewType
UserID = NewType('UserID', int)
admin_user_id: UserID = UserID(524313)
4.1 타입 앨리어스
타입 앨리어스를 사용하여 복잡한 타입 구조를 간결한 이름으로 표현할 수 있습니다.
Vector = List[float]
def normalize(vec: Vector) -> Vector:
magnitude = sum(x**2 for x in vec) ** 0.5
return [x / magnitude for x in vec]
5. 제네릭(Generic) 타입
제네릭 타입을 사용하면 하나의 함수나 클래스를 여러 타입으로 사용할 수 있습니다. typing.Generic
클래스를 사용하여 제네릭 타입을 정의할 수 있습니다.
from typing import TypeVar, Generic
T = TypeVar('T')
class Box(Generic[T]):
def __init__(self, content: T) -> None:
self.content = content
int_box = Box(123)
str_box = Box("hello")
6. 고급 예제
다음은 타입 어노테이션을 활용하여 작성된 조금 더 복잡한 예제입니다.
from typing import List, Dict, Union, Callable
def process_data(data: List[Union[int, float, str]]) -> Dict[str, Union[int, float]]:
result: Dict[str, Union[int, float]] = {'total': 0, 'numeric_count': 0}
def is_number(val: Union[int, float, str]) -> bool:
return isinstance(val, (int, float))
for item in data:
if is_number(item):
result['total'] += item # 타입 경고는 막아준다.
result['numeric_count'] += 1
return result
mixed_data: List[Union[int, float, str]] = [10, '20', 30.5, 'forty', '60', 70.2]
output = process_data(mixed_data)
print(output)
# {'total': 110.7, 'numeric_count': 3}
7. 정적 타입 체크 툴
타입 어노테이션은 정적 타입 체크 툴과 함께 사용될 때 가장 유용합니다. 파이썬에서는 mypy, Pyright, Pylance 같은 툴들이 많이 사용됩니다.
예를 들어, mypy
는 다음과 같이 사용됩니다:
mypy script.py
이러한 툴은 코드의 타입 일관성을 검사하고 예상치 못한 타입 오류를 예방하는 데 매우 효과적입니다.
8. 결론
타입 어노테이션은 파이썬의 강력한 기능으로, 코드의 가독성을 높이고 유지보수를 쉽게 하며 오류를 사전에 예방하는 데 큰 도움을 줍니다. 또한, 정적 분석 도구와 결합하여 대규모 프로젝트에 더욱 안정성을 부여합니다. 이 강좌를 통해 여러분이 타입 어노테이션을 잘 활용할 수 있게 되어, 보다 견고한 파이썬 코드를 작성하길 기대합니다.