오늘은 파이썬 관련 정적 타입 검사에 대해서 소개하는 시간을 가져보도록 하겠습니다.
정적 타입 검사가 왜 필요한 이유
파이썬은 동적 타입 언어로 구성되어 있기 때문에 다른 언어에 비해서 유연하고 빠르게 개발을 할 수 있습니다. 그렇다면 정적 타입 검사는 왜 필요할까요? 정적 타입 검사가 필요한 이유를 알기 위해서는 동적 타입 언어의 특징에 대해서 이해를 하고 있어야 합니다. 동적 타입 언어의 특징은 크게 두 가지가 있습니다.
첫 번째는 코드가 실행될 때 타입을 체크하는 것입니다. 위 코드를 보면 if False: 부분은 실행이 되지 않기 때문에 1 + "two"가 타입 에러를 발생시키는 코드이지만 에러가 발생하지 않습니다.
두 번째는 실행 시간 동안 변수의 타입을 변경할 수 있다는 것입니다. thing 변수에 str 값을 대입한 후에 float 값도 대입할 수 있습니다.
이런 특징으로 인해서 파이썬의 에러는 대부분 코드를 작성할 때가 아니라 테스트 혹은 코드를 실행할 때 발견합니다. 이는 규모가 작은 프로젝트에서는 문제가 되지 않을 수 있지만 규모가 큰 프로젝트에서는 오히려 파이썬의 개발 속도가 느려지는 원인이 되기도 합니다.
아래는 2020년에 파이썬 개발자들에게 실시한 설문조사 결과입니다. 설문 내용은 파이썬에 추가적으로 필요한 기능에 대한 것이었는데요, 설문 결과를 통해 정적 타입 검사 기능을 강력하게 요구하고 있다는 사실을 확인할 수 있습니다.
정적 검사 도구
지금까지는 동적 타입 언어인 파이썬에 정적 타입 검사가 왜 필요할까에 대해서 알아보았습니다. 지금부터는 파이썬과 관련된 대표적인 정적 타입 검사에 대해서 소개하도록 하겠습니다.
파이썬과 관련된 대표적인 정적 타입 검사 도구로는 mypy, pyright, pyre-check가 있습니다. 이외에도 pytype, pychecker, pycontracts 등 다양한 정적 검사 도구가 존재합니다.
mypy
mypy는 가장 널리 사용되는 최초의 파이썬 정적 타입 검사 도구입니다. 2012년 pycon 발표된 내용에 따르면 Typescript와 같이 python에 타입을 추가한 새로운 언어로 설계하고자 했음을 알 수 있습니다. 이후 2014년에 Guido van Rossum의 제안에 따라 type hint를 사용해 타입을 선택적으로 검사할 수 있도록 재작성되었습니다. 현재는 파이썬 정적 타입 표준을 정의하는 PEP 484에 맞추어 검사를 수행해 주는 대표적인 파이썬 정적 타입 검사 도구입니다.
# 설치
pip install mypy
# 실행
mypy program.py
설치, 실행은 위 명령어를 통해 간단하게 수행할 수 있습니다.
동적 타입 함수 vs 정적 타입 함수
mypy는 동적으로 지정된 함수는 검사하지 않습니다. greeting 함수는 문자열과 숫자를 더하는 연산을 수행할 것이라고 예상되지만 mypy를 수행하면 success 결과가 나옵니다.
mypy가 함수를 인식할 수 있도록 정적 타입 형태로 수정을 해야 합니다. 위와 같이 코드를 수정하면 정상적으로 검사를 수행합니다.
type hint가 없는(=정적 타입으로 구성되지 않은) 코드에 대해서 검사를 하지 않는 이유
- mypy의 목적에는 코드를 이해하기 쉽게 만드는 것이 포함되어 있음. type hint가 없는 코드에 대해서도 타입 검사를 하게 되면 오히려 사용자가 type hint를 작성하지 않아 가독성이 떨어질 것이라고 판단
- type 검사를 하는 것과 하지 않는 것이 명시적으로 구별되는 것이 좋다. type hint가 없는 코드 중 일부는 타입을 유추할 수 있고 일부는 타입을 유추할 수 없다. 만약 type을 유추해서 검사를 하게 된다면 모듈의 어떤 부분이 type 검사 되고 있는지, 어떤 부분이 안되고 있는지 구별하기 어려움
- 기술적으로도 type hint가 없는 코드에 대해서는 타입 검사를 하지 않는 것이 더 쉬움
옵션
mypy와 관련된 옵션으로는 여러 가지가 있는데 대표적으로는 다음과 같습니다. 상황에 따라서 필요한 옵션을 선택하면 될 것 같습니다.
--ignore-missing-imports | 누락된 모듈에 대한 에러를 무시 |
--strict | 타입 관련 모든 가능한 오류를 찾는 데 유용 |
--disallow-untyped-defs | 모든 함수에 타입 힌트를 적용하려는 경우 유용 |
--disallow-incomplete-defs | 일부만 타입 주석이 있는 함수를 허용하지 않음 |
--check-untyped-defs | 타입 힌트가 없는 함수 내부의 코드도 검사 |
--no-implicit-optional | None 을 허용하려는 모든 타입 힌트에 명시적으로 Optional을 지정하도록 안내 |
설정 파일
그리고 mypy는 우선 순위에 따라서 설정 파일을 읽습니다. 실행 파일에 따라서 다른 옵션을 지정해야 하는 경우가 있기 때문에 우선순위에 따라서 설정 파일을 읽는 것을 지원하는 것으로 보입니다.
1. ./mypy.ini
2. ./.mypy.ini
3. ./pyproject.toml
4. ./setup.cfg
5. $XDG_CONFIG_HOME/mypy/config
6. ~/.config/mypy/config
7. ~/.mypy.ini
지역 변수 추론
함수에 타입 힌트를 추가하면 mypy는 다음과 같은 방법으로 지역 변수를 추론합니다.
1. 타입 힌트
변수 선언에 타입 힌트가 있을 경우 해당 타입 힌트를 따릅니다. ex) x: int = 5
2. 리터럴 값
타입 힌트가 없지만 리터럴 값을 할당하는 경우 그 값의 타입을 따릅니다. ex) x = 5
3. 연산자
피연산자 타입을 고려하여 타입 추론합니다. ex) x = “Hello” + “World”
4. 조건문
user_id 값은 int 혹은 str 형이 가능한 상황입니다. if isinstance(user_id, int) 조건에 걸린 경우 user_id 값인 int 형으로 추론하며 else 문에 걸린 경우 str 형으로 추론합니다.
Types from libraries
mypy는 파이썬 관련 정적 타입 검사 도구이기 때문에 파이썬에서 자주 사용하는 라이브러리에 대해서는 어떤 함수가 어떤 값을 리턴하는지 아는 경우가 있습니다. 위 함수에서 template_path.read_text() 함수가 str 값을 리턴하는 것으로 알고 있기 때문에 정적 타입 검사를 수행하면 통과합니다. mypy가 모르는 라이브러리 함수는 .pyi 확장자를 가지는 stub 파일을 통해 아래와 같이 타입 힌트를 제공할 수 있습니다.
결론
동적 타입 언어인 파이썬에 정적 타입 검사 도구는 왜 필요한지, 정적 타입 검사 도구 중 가장 대표적인 mypy는 어떤 것인지에 대해서 살펴보았습니다. mypy는 적용하기도 쉽고 많은 오픈소스 프로젝트에서도 사용하고 있는 도구이기 때문에 타입 에러에 대한 불편함을 겪고 있으시다면 이번 기회에 적용해 보는 것도 좋은 방법이라고 생각합니다.
참고
'Language > Python' 카테고리의 다른 글
[Python] Excel 파일 암호화 (0) | 2023.11.12 |
---|---|
[Python] Decimal이란 (0) | 2023.07.09 |
[ Python ] 점프 투 파이썬 전면 개정 2판 서평 (0) | 2023.07.01 |
[Python] *args, **kwargs (0) | 2022.07.03 |
[Python] mac 경로 설정 (7) | 2022.01.14 |