이전까진 타입 스크립트, 코틀린등을 쓰다가 파이썬으로 넘어올때 가장 불편했던건 타입이 없던것이었다. 처음 간단하게 스크립트를 작성할때는 편할 수 있지만 결국 혼자 작업하는게 아닌 이상 타입이 있는게 무조건 편하고 속도도 빠르다.
다행히 파이썬 3.5부터 타입 힌팅을 제공하는데 개발하면서 유용하게 쓸 수 있도록 정리해보았다.
타입의 등장
What’s New In Python 3.5 — Python 3.5.9 documentation
configparser configparser now provides a way to customize the conversion of values by specifying a dictionary of converters in the ConfigParser constructor, or by defining them as methods in ConfigParser subclasses. Converters defined in a parser instance
docs.python.org
파이썬 3.5부터 typing 라이브러리가 추가되었고, 이제 사용자가 변수에 타입을 달 수 있게 되었다.
이제 typing 라이브러리의 Any , Union, Tuple, Callable, TypeVar 을 사용해서 타입 힌트를 줄 수 있다. 런타임에 __annotations__ 로 타입을 확인할 수는 있지만, 런타임에 타입을 체크하는것은 아니고, mypy 같은 thid party 타입 체커를 사용하면 타입을 체크할 수 있다. 공식문서에는 어노테이션이라고 소개하는데, 여기서 설명하는 어노테이션은 주석이라는 의미이고 파이썬에서 사용하는 @property 같은 데코레이터와 다르다.
타입 지정
타입을 지정하고자 하는 변수에 :타입 이렇게 사용해주면 된다.
빌트인 타입은 import 없이 사용할 수 있다.(int, str, float, list, dict, …)
user_profile: dict[str, list[int]] = { 'key1': [1, 2, 3], 'key2': [], 'key3': [12900, 18900] }
타입 별칭(type alias)은 이렇게 만들 수 있다.
Vector = list[float] # 할당을 통해서 만들 수 있다.
comissions: Vector = [1.0, 19.8, 1.15]
NewType 으로 새로운 타입을 만들 수도 있다.이렇게 사용할 경우, 다른 사람과 협업할때 보다 가독성 좋은 코드를 작성할 수 있다. (숫자 1이 단순한 숫자 1이 아닌 user_id라고 표시할 수 있음)
UserId = NewType('UserId', int)
def find_by_user_id(user_id: UserId) -> Any: return { }
find_by_user_id(1) # 실행이 안되지는 않지만 IDE에서 경고 표시가 뜬다.
find_by_user_id(UserId(1))
Any : 모든 타입에 대응된다. 특정한 타입을 지정해줄 수 없을 때 Any를 사용한다. 타입 스크립트의 any와같은 용도로 사용한다고 보면된다.(코틀린이라면 Unit)
Union : 두 가지 이상의 타입을 지원한다. 예를 들어 변수 profile_value의 타입이 str이 될 수 도 있고, int가 될 수도 있을때 Union을 사용한다.
파이썬 3.10 버전 이후 부터는 |연산자를 통해 타입을 union할 수 있다. 😽
profile: dict[str, Union[str, int]] = { 'user_name': 'Mark', 'age': 20, 'joined_at': '2024-03-01' }
profile: dict[str, str | int] = {
'user_name': 'Mark',
'age': 20,
'joined_at': '2024-03-01'
}
Callable : 함수를 지원한다. 파이썬은 함수가 일급객체이므로 함수의 인자로도 사용할 수 있는데 그럴때 타입을 지정해줄 수 있다.
Callable[[인자의 타입, 인자의 타입], 리턴 타입]
def do_something(on_success: Callable[[], str]) -> str:
return on_success()
def on_success():
print('success!')
return 'success'
do_something(on_success)
TypeVar : Generic을 사용할 수 있다. 여기서 추가로 타입을 지정할 수도 있다. 공식문서를 보면 좀 더 잘 활용할 수 있는 방법이 제시되어있는데 아직 파이썬 Generic이 손에 익지 않아 이 정도로면 예시를 작성해보았다. 이 부분에 대해선 조금 더 공부가 필요하다.
T = TypeVar('T')
def repeat_or_plus(x: T) -> T:
print(x + x)
return x + x
repeat_or_plus('test')
repeat_or_plus(3)
A = TypeVar('A', str, int)
def repeat_or_plus(x: A) -> A:
print(x + x)
return x + x
repeat_or_plus('test')
repeat_or_plus(3)
repeat_or_plus([1, 2, 3]) # 실행은 할 수 있지만 IDE에서 경고 표시가 뜬다.
인사이트
type check도 도입해서 타입 체크를 엄격하게 하면 좋지만, 개발하는 입장에서 이 함수의 인자가 어느 타입이고 어떤 타입을 리턴하는지 코드를 읽으면서 바로 알 수 것만으로도 아주아주 도움이 된다.
지금 다니는 회사에 합류해서 틈날때마다 타입을 도입하고는 있지만 아직 파이썬의 타입 시스템이 완전하지 않기 때문에 타입 붙여주기 애매한것도 정말 많다.
타입이 없다는건 간단한건 개발을 정말 빨리 할 수 있지만 대규모 시스템에서는 타입이 없으면 오히려 개발이 더 느려지는것 같기도 하다. 파이썬 생태계에도 타입을 쓰는게 당연한 일이 되는 날이 왔으면 좋겠다.(내 바램)
References
26.1. typing — Support for type hints — Python 3.5.9 documentation
26.1. typing — Support for type hints Source code: Lib/typing.py This module supports type hints as specified by PEP 484. The most fundamental support consists of the types Any, Union, Tuple, Callable, TypeVar, and Generic. For full specification please
docs.python.org
26.1. typing — Support for type hints — Python 3.5.9 documentation
26.1. typing — Support for type hints Source code: Lib/typing.py This module supports type hints as specified by PEP 484. The most fundamental support consists of the types Any, Union, Tuple, Callable, TypeVar, and Generic. For full specification please
docs.python.org
파이썬의 typing 내장 모듈로 타입 표시하기
Engineering Blog by Dale Seo
www.daleseo.com
'Django,Python' 카테고리의 다른 글
[Django] Custom Command 만들기 (0) | 2024.04.06 |
---|---|
[Django] on_delete=CASCADE (1) | 2024.03.23 |
[Django] Template script에서 view데이터 사용하기 (1) | 2024.02.24 |
MAMP로 Python CGI 테스트 해보기 (1) | 2024.01.12 |
[Django] Django ORM Coalesce 사용하기 (0) | 2023.09.22 |