Python - 타입 힌트 (Type Hint)

3 분 소요

파이썬 = 동적언어

타입힌트에 대해 이해하려면 우선 동적언어와 정적언어의 차이부터 이해해야한다.

C 나 Java 같은 언어를 접해봤다면 해당 언어들에서 변수나 함수를 선언할 때 해당 변수의 자료형이 무엇인지, 혹은 함수가 리턴하는 값의 자료형은 무엇인지 입력해야 한다는 걸 알 것이다.

int sum(int a, int b) {
    return a+b;
}

정적(static) 언어는 이처럼 변수 선언시 자료형을 지정하고 컴파일 과정에서도 변수에 맞지 않는 타입이 있는 경우에는 컴파일이 되지 않는다.
(**대부분의 정적 언어들이 컴파일 언어이긴 하지만 정적 언어와 컴파일 언어는 다른 개념이니 주의하자)

이와 반대로 파이썬 및 자바스크립트 같은 언어들은 동적(dynamic) 언어로 실행과정에서 변수 안의 값을 확인하기 때문에 타입을 미리 선언하지 않아도 되고 심지어 변수의 타입이 바뀌어도 된다.

>>> number = 1
>>> type(number)
<class 'int'>
>>> number = "one"
>>> type(number)
<class 'str'>

타입 힌트(Type Hint)

이처럼 파이썬은 동적 언어이기 때문에 코드를 작성할 때 굳이 변수의 타입을 표시하지 않아도 된다.

그런데 파이썬 3.5 버전부터 타입 힌트 기능이 생겼고, 필수는 아니지만 코드를 읽는 개발자를 위해 작성된 변수의 타입이 무엇인지 말그대로 ‘힌트’를 줄 수 있게 되었다.

문법은 아래처럼 변수명 뒤에 ‘:’를 넣고 타입을 표기하면 된다. 함수의 경우엔 ‘->’ 를 사용해서 리턴하는 값의 타입이 무엇인지 표기한다.

number: int = 1

def read_number(number: int) -> str:
    return f"The number is {str(number)}"

타입 힌트를 왜 쓸까?

간결함, 단순함, 공백 등을 핵심 철학으로 하는 파이썬에서 타입힌트를 왜 사용해야 될까?

위의 예시처럼 간단한 코드라면 타입힌트를 쓰는게 오히려 작성해야 되는 코드도 길어지고 불편할 수 있다.

그런데 실제 프로젝트를 위해 코드를 작성하다 보면 내용이 너무 많아지고, 어디선가 선언된 변수를 스크롤을 한참 내린 뒤에서야 다시 보게 되는 경우가 생기면서 코드를 파악하기도 어렵고 타입 에러가 발생할 확률도 높아진다.

이럴 때 타입 힌트를 쓴다면 선언된 변수에 어떤 타입이 들어가야 하는지 파악하기 쉬워질 수 있고, mypy 같은 타입 체크 툴을 사용해서 컴파일 언어처럼 프로그램 실행 전에 에러가 발생할 수 있는 부분을 미리 확인할 수도 있게 된다.

Typing

타입 힌트를 쓸 때 int, str, float, bool 같은 기본 타입들도 쓰지만 그 외 다른 형태의 자료를 사용하게 되는 경우도 많다.

그럴 때 파이썬 내장 모듈인 typing을 사용해서 아래와 같이 타입 힌트를 하면 된다.

from typing import List, Set, Dict, Tuple, Optional

# 기본 내장 타입
x: int = 1
x: float = 1.0
x: bool = True
x: str = "test"
x: bytes = b"test"

# Python 3.9 이상 버전에서의 컬렉션 자료형
x: list[int] = [1]
x: set[int] = {6, 7}

# Python 3.8 이하 버전에서의 컬렉션 자료형 
# 맨앞 글자가 대문자이며, typing 모듈에서 import 해야한다.
x: List[int] = [1]
x: Set[int] = {6, 7}

# 맵핑형 자료
x: dict[str, float] = {"field": 2.0}  # Python 3.9+
x: Dict[str, float] = {"field": 2.0}

# 고정 길이의 튜플은 각 원소의 타입을 입력
x: tuple[int, str, float] = (3, "yes", 7.5)  # Python 3.9+
x: Tuple[int, str, float] = (3, "yes", 7.5)

# 가변 길이의 튜플은 타입 한 종류와 말줄임표를 이용한다.
x: tuple[int, ...] = (1, 2, 3)  # Python 3.9+
x: Tuple[int, ...] = (1, 2, 3)

# None이 들어갈 수 있는 변수는 Optional을 사용한다.
x: Optional[str] = some_function()

# None이 들어가선 안되는 변수라면 assert를 사용할 수 있다.
assert x is not None
print(x.upper())

# 사용자 정의 클래스
class Book:
    ...

def get_book(id: int) -> Book:
    ...

출처: mypy type hints cheat sheet (python3)

</br>

개인적인 타입 힌트 사용후기

개발자들 사이에서도 정적언어와 동적언어에 대한 선호도는 많이 갈리는 것 같다. 개인적으로는 파이썬으로 프로그래밍을 시작해서 그런지 타입을 표기하는 것이 아직 익숙하지는 않은데, 주변에 타입 표기를 하지 않는 것이 싫어서 파이썬을 좋아하지 않는 개발자들도 있는 것을 보면 장단점이 확실한 것 같다.

분명 타입 힌트를 쓰는 개발 문화가 잘 갖춰진 환경이라면 좋은 요소가 될 수 있을 것 같다. 다만 개인적으로 단점이라고 생각했던 부분들은 타입 힌트가 어디까지나 파이썬을 쓰는데 있어서 필수 요소가 아니라는 점에서 발생했다.

일단 필수요소가 아니고 사용자의 편의와 가독성을 위해 추가된 기능이어서 실제로 코드가 실행되는 데에는 아무런 영향을 미치지 않는다. mypy 같은 타입 체크 툴을 이용해서 타입 에러를 잡아낼 수는 있지만 그렇다고 컴파일 언어처럼 실행 속도가 빨라지지는 것은 아니다.

그리고 강제성이 없다보니 모든 파이썬 프로젝트에서 타입 힌트가 사용되지 않아서 모두가 타입 힌트를 쓰는 것이 아니라면 오히려 가독성을 해치게 될 수 있을 것 같다.

회사에서 개발 중인 프로젝트에 타입힌트를 써보려고 했지만 이미 타입힌트 없이 작성된 코드가 많을뿐더러, 오픈소스를 사용하는 경우에는 타입 힌트가 없는 경우도 많기 때문에 어디서는 타입 힌트가 사용되고 어디서는 사용되지 않아 오히려 가독성이 떨어트리는 문제가 발생했다.

그럼에도 파이썬에서 정적언어로 넘어가는 연습 차원에서는 타입 힌트 사용이 큰 도움이 될 것 같다. 그리고 다같이 타입 힌트를 쓰는 개발 문화가 잘 정착된 환경이라면 분명 그 장점을 다 살릴 수 있을 듯 하다.

댓글남기기