파이썬 타입 어노테이션

파이썬은 동적 타이핑(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. 정적 타입 체크 툴

타입 어노테이션은 정적 타입 체크 툴과 함께 사용될 때 가장 유용합니다. 파이썬에서는 mypyPyrightPylance 같은 툴들이 많이 사용됩니다.

예를 들어, mypy는 다음과 같이 사용됩니다:

mypy script.py

이러한 툴은 코드의 타입 일관성을 검사하고 예상치 못한 타입 오류를 예방하는 데 매우 효과적입니다.

8. 결론

타입 어노테이션은 파이썬의 강력한 기능으로, 코드의 가독성을 높이고 유지보수를 쉽게 하며 오류를 사전에 예방하는 데 큰 도움을 줍니다. 또한, 정적 분석 도구와 결합하여 대규모 프로젝트에 더욱 안정성을 부여합니다. 이 강좌를 통해 여러분이 타입 어노테이션을 잘 활용할 수 있게 되어, 보다 견고한 파이썬 코드를 작성하길 기대합니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다