Python: static type checking - mypy
Background) Static-type and Dynamic-typed checking
- python์ด์ ์ ๋น๊ต์ ์ ํต์ ์ธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ์ํ๋ c, c++, java ๋ฑ์ ์ธ์ด๋ฅผ ์ฌ์ฉํด๋ณด์ ๋ถ๋ค์ ๋ค์๊ณผ ๊ฐ์ ํํ๋ก ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์ต์ํ์ต๋๋ค.
int a = 10
- ํ์ง๋ง, ์ฐ๋ฆฌ ์๋ํ python์ ๊ฒฝ์ฐ๋ ๋ค์๊ณผ ๊ฐ์ฃ . ์์ฃผ ์งง๊ณ ๊ฐํธํด์ง๋๋ค.
a = 10
a = "string"
- ์์ ํด๋น variable์ type์ด ๋ฌด์์ธ์ง ์๋ ค์ฃผ์ง ์์๋ ๋๋ค๋ ๊ฒ. ์ด ๊ฒ์ด ์ฌ์ํ ์ฐจ์ด์ผ ์๋ ์์ง๋ง, ์ด ๊ฐํธํจ์ด python์ด ์ง๊ธ์ฒ๋ผ ๋ง์ ๋์ค๋ค์๊ฒ ๊ด์ฌ์ ๋๊ฒ ๋ ์์ธ ์ค ํ๋๋ผ๊ณ ์ ๋ ์๊ฐํด์. ํ์ง๋ง, ์์ฒ๋ผ ์ฝ๋๊ฐ ์งง๋ค๋ฉด ๋ฌธ์ ๊ฐ ๋์ง ์์ง๋ง, ์ฝ๋๊ฐ ๊ธธ์ด์ง๊ณ ๋ค๋ฅธ ์ฌ๋๋ค๊ณผ ์ฝ๋๊ฐ ๊ณต์ ๋๊ธฐ ์์ํ๋ฉด ์ ์ฐจ ๋ฌธ์ ๊ฐ ์๊ฒจ ๋ฉ๋๋ค.
Static-type checking
- ์๋ฌดํผ, C์ ๊ฐ์ด, ๋ฏธ๋ฆฌ ๊ฐ โ๋ณ์โ์ ๋ณ์๋ค์ ์ฒ๋ฆฌํ๋ โํจ์โ๋ค์ ๋ํด์ ์ฝ๋ ์์ฑ์์ type์ด ์ ์๋๋ ๊ฒ์ ์๊ตฌํ๋ ์ธ์ด๋ค์ ์ ์ ํ์ ์ธ์ด๋ผ๊ณ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ runtime(์ฝ๋ ์คํ) ์ด์ ์ธ ์ปดํ์ผ ํ์์์ type์ ์ฒดํฌํ๊ณ ๋์ด๊ฐ๊ฒ ๋์ฃ . ์ด๋ฅผ ํตํด, ์กฐ๊ธ์ ๋น ๋ฅด๊ฒ ํด๋น ์ฝ๋์์ ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ์ ๋ค์ ํ์ ํ ์ ์์ต๋๋ค.
- ๋ฌผ๋ก , haskell์ ๊ฒฝ์ฐ๋ ์์ธ์ ์ผ๋ก type์ ๋ฏธ๋ฆฌ ์ ์ธํ์ง ์๋๋ผ๋, ์ด๋ ์ ๋๋ โํ์ ์ถ๋ก โ์ ํ ์ ์๋ค๊ณ ํฉ๋๋ค. ์ด๋, ํด๋น โ(ํ์ ์ด ์๋ ค์ง์ง ์์) ๋ณ์โ๊ฐ โ์ด๋ค ํ์ ์ ๋ณ์์ ๊ด๋ จ๋์ด ์๋์งโ, ๊ทธ๋ฆฌ๊ณ โ์ด๋ค ํ์ ์ ํจ์๋ค๊ณผ ์ฐ๊ฒฐ๋์ด ์๋์งโ๋ฑ์ ํตํด ์ด๋ ์ ๋๋ ํ์ ํด๋ผ ์ ์๋ค๊ณ ํ๋๋ฐ, ์ด๋ค ์๋ฏธ์์, ์ด๋ dynamic-type chekcing๊ณผ ์ ์ฌํ๋ค๊ณ ๋๊ปด์ง๊ธฐ๋ ํด์(๋ค๋ง, ์ด ๋ถ๋ถ์ ์ ์ ๋ณด๊ฐ ์ถฉ๋ถํ์ง ์์ผ๋ฏ๋ก ๋์ด๊ฐ๊ฒ ์ต๋๋ค).
- ์ฌ๊ธฐ์ ์ํ๋ ์ธ์ด๋ค๋ก, C, C++, Go, Haskell, Java, Kotlin, Rust, Scala ๋ฑ์ด ์์ต๋๋ค.
Dynamic-type checking
- ๋ฐ๋๋ก python์ฒ๋ผ, ๊ฐ ๋ณ์๋ค์ type์ ์ ์ํ์ง ์๊ณ ๋ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๋ ๊ฒฝ์ฐ๋ฅผ ๋์ ํ์ ์ธ์ด๋ผ๊ณ ํฉ๋๋ค. ์ฆ, ๋ฏธ๋ฆฌ ์ ์๋์ด ์์ง ์๊ธฐ ๋๋ฌธ์ โ๋๋ ค๋ด์ผ ๋ฌธ์ ๊ฐ ์๋์ง ์ ์ ์๋คโ๋ผ๋ ๋ง์ ๋๋ค. ๋ง์ฝ, 1๋ฒ ๋๋ฆฌ๋๋ฐ 10์๊ฐ์ด ๊ฑธ๋ฆฌ๋ ์ฝ๋๊ฐ ์๋ค๋ฉด, ์ด๋ฅผ dynamic-type์ผ๋ก ์ฝ๋ฉํ์ฌ, 5์๊ฐ์ด ์ง๋ ๋ค์์์ผ ์ ์ ์๋ค๋ฉด, ์ข ๋ฌด์ญ๊ฒ ์ฃ ?
- ์ฌ๊ธฐ์ ์ํ๋ ์ธ์ด๋ค๋ก๋ python, Ruby, javascript, lisp ๋ฑ์ด ์์ต๋๋ค.
Hybrid type checking
- python์ dynamic-type checking ์ธ์ด๋ก ์์๋์์ต๋๋ค๋ง, ์ค๋ ๋งํ ๊ฒ๊ณผ ๊ฐ์ด, ์ ์ type์ ๋ฏธ๋ฆฌ ์ง์ ํ๋ฉด์ ์ฝ๋ฉํ๋ ๋ฐฉํฅ์ผ๋ก ๋์๊ฐ๊ณ ์์ต๋๋ค. ํ๋ก์ ํธ์ ๊ท๋ชจ๊ฐ ์ปค์ ธ๊ฐ๋ฉด์ ์ ์ง๋ณด์ ๋ฌธ์ ๋ก ์ธํด์ ๊ทธ๋ด ๊ฐ๋ฅ์ฑ์ด ๋๋ค, ๋ผ๊ณ ์ ๋ ์๊ฐ๋์ด์. ๋ณดํต, dynamic-type ์์ static-type์ผ๋ก ๊ฐ๋ ๊ฒฝ์ฐ๋ ์ ์์ต๋๋ค.
- ์กด์ฌํ๋ ๋ชจ๋ ์ฝ๋์ ๋ํด์ static-type์ ํํ๋ก ์ฝ๋ฉ๋์ด์ผ ํจ์ ๊ฐ์ ํ๋ ๊ฒ์ ์ข ์ด๋ ค์ด ์ผ์ด์ฃ . ์ฒ์๋ถํฐ ๊ทธ๋ ๊ฒ ํ์ผ๋ฉด ๋ชจ๋ฅผ๊น. ๊ทธ๋์, ํ ์ ์๋ ๋ถ๋ถ๋ง static-type checking์ ํตํด ๋ถํ์ค์ฑ์ ์ค์ด์, ๋ผ๋ ๊ฒ์ด ์ด๋ฌํ ์์ฌ ์๋ type checking์ธ ์ ์ด์ฃ .
type conversion
- implicit type converstion(ํ๋ก๊ทธ๋๋จธ ๋ชฐ๋ ์์์ ํ์ ๋ณ๊ฒฝํ๋ ๊ฒ)๊ณผ explict type conversion(ํ๋ก๊ทธ๋๋จธ๊ฐ โ๋ฐ๊ฟ!โ๋ผ๊ณ ํ๋ ๊ฒ)์ผ๋ก ๊ตฌ๋ถ๋ฉ๋๋ค. ๋๋ฒ๊น ์์ ๋ฐ์ํ๋ ๋ฌธ์ ๋ฅผ ์์ ๋ ค๋ฉด, ๊ฐ๋ฅํ explicitํ ๊ฒ์ด ๋ ์ข๊ธฐ๋ ํ์ฃ .
Back to Python: Type hinting
- ์๋ฌดํผ, python์ผ๋ก ๋ค์ ๋์์์ ๋ณด๊ฒ ์ต๋๋ค. ์์ ๋งํ ๊ฒ์ฒ๋ผ python์ ๋์ ํ์ ์ธ์ด์ ๋๋ค. ์๋์ฒ๋ผ ํ์ ์ง์ ํ์ง ์๊ณ ์๋ฌด ๊ฐ์ด๋ ๋ง ์ง์ด๋ฃ์ด๋ ๋์ฃ .
var_int = 10
var_str = "33"
var_float = 1.333
- ํ์ง๋ง, ์ด๋ ๊ฒ ํ์ง ์๊ณ type์ ์๋ ค์ฃผ๋ฉด์ ์ฝ๋ฉ์ ํ๋ ค๊ณ ํฉ๋๋ค. ๋ค๋ง, type์ ์๋ ค์ค ๋ฟ, type checking์ ํ์ง๋ ์์ต๋๋ค. ์ฆ, ๊ทธ๋ฅ โ์ฃผ์โ๋ค๋ ๊ฒ์ฒ๋ผ ๊ฐ ๋ณ์์ ํจ์์ ๋ํด์ type์ ์ ์ด์ฃผ๋ ๊ฒ์ด์ฃ . ํด๋น ๋ด์ฉ์ PEP-484์ ์์ฑ๋์ด ์์ผ๋ฉฐ, ๊ฐ๋จํ ํ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
:์ ์ฌ์ฉํด์ ๋ค์ type์ ์ ์ด์ฃผ๋ฉด ๋ฉ๋๋ค. python native type์ด๋ผ๊ณ ํ ์ ์๋ ๊ฑฐ์ ๋๋ถ๋ถ์ type๋ค,bool/str/int/float/list/dict/tuple์ ๋ํด์ ์ง์ ํด์ค ์ ์์ต๋๋ค.
# bool/str/int/float/list/dict/tuple
def greeting(param1: str, param2: int) -> str:
# explicit type conversion for parma2
return "Hi "+ param1+str(param2)
########################################
var1: str = "aaa"
var2: int = 1000
var3: float = 14.5
########################################
print(
greeting(var1, var2)
)
print(
greeting(var1, var3)
)
- ์คํ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. python์ type-hinting, ์ฆ type์ด ๋ฌด์์ธ์ง ์ ๊ธฐ๋ ํ์ง๋ง, type-checking์ ํ์ง๋ ์์์. ๋ฐ๋ผ์, ์์ ํจ์์์
param2์์ ์๋๋,int๋ค์ด์ผ ํ๋๋ฐ,float์ด ๋ค์ด์๋, ๋ฌธ์ ๊ฐ ์์ด ์คํ๋ฉ๋๋ค.
Hi aaa1000
Hi aaa14.5
mypy: type-checking
- ํ์ง๋ง, ์ฐ๋ฆฌ๋ type-checking์ ํ๊ณ ํ๋ก๊ทธ๋จ์ ๋๋ฆฌ๊ณ ์ถ์ต๋๋ค. ์ด๋ฅผ ์ํด์๋
mypy๋ผ๋ ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํด์ค์ผ ํ์ฃ . - ์ผ๋จ
mypy๋ฅผ ์ค์นํฉ๋๋ค.
pip install mypy
- ๊ทธ๋ฆฌ๊ณ , ์๋์ ๊ฐ์ด ํด๋น ํ์ผ์ ๋ํด์ ์ปค๋งจ๋๋ผ์ธ์์ ๋๋ ค๋ณด๋ฉด ๋ฉ๋๋ค.
mypy test.py
- ๊ฐ๋จํ์ง๋ง, ์ค๋ฅ๋ฅผ ์ก์์คฌ์ฃ .
test.py:29: error: Argument 2 to "greeting" has incompatible type "float"; expected "int"
Found 1 error in 1 file (checked 1 source file)
wrap-up
- ์ฌ์ค ์ฒ์ ํ๋ก๊ทธ๋๋ฐ์ ๋ฐฐ์ธ ๋๋ dynamic-type์ด ํธํ์ง๋ง, ์๊ฐ์ด ๊ฐ์๋ก ์ด๋ ์ ๋๋ static์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ๋ฅผ ๋ฐ๋ ๋๊ฐ ์์ต๋๋ค. ์ค์ค๋ก๋ฅผ ๋ฏฟ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์, ๋์ ์ค์๋ฅผ ๋ฏธ๋ฆฌ ๋ง์์ค ์ ์๊ธฐ๋ฅผ ๋ฐ๋ผ๋ ๋ง์๋ ์๊ณ ์.
- static type์ผ๋ก ์ฒ๋ฆฌํ ๋์ ๊ฐ์ ์ด๋ผ๋ฉด, ์๋, ์ต์ํ annotation์ผ๋ก ๋ณ์์ ํจ์์ ํ์ ์ ์ ์ํ๋ฉด์ ์ฝ๋ฉํ ๋์ ๊ฐ์ ์ด๋ผ๋ฉด, ๊ทธ ํจ์์ ํ์ดํ๋ผ์ธ์ด ์ด๋ค ํํ๋ก ๋๋์ง, ๋๋ต์ ๊ตฌ์ํ ์ ์๋ค๋ ๊ฒ์ด์ฃ . ์๋ฅผ ๋ค์ด, ๋ค์ ๋ ํจ์๋ฅผ ๋ณธ๋ค๋ฉด, type-hinting์ ํ ๋ โ์ฝ๋์ ๊ฐ๋ ์ฑโ์ด ์๋นํ ์ฌ๋ผ๊ฐ์ ์ ์ ์์ต๋๋ค(๋ฌผ๋ก ๋ณ์๋ช ์ ์ฌ์ฉํด์ type hinting์ ํ ์๋ ์๊ธด ํฉ๋๋ค๋ง)
def func_without_typehinting(a, b, c, d):
return [ str(a)+str(b)+x+c for x in d]
def func_with_typehinting(a:int, b:float, c:str, d:list):
return [ str(a)+str(b)+x+c for x in d]
- ๋ค์ ๋งํ์ง๋ง, ์ ๋ ๊ฒ ์จ์ค๋ค๊ณ ํด์, python์ ์คํ์ํฌ ๋ ์์์ type์ ์ก์์ฃผ๋ ๊ฒ์ ์๋๋๋ค. ๊ทธ๋๋, โ์ ๊ฐ ์ง์ static-type checking์ ํ ์ ์๋คโ๋ผ๋ ๊ฒ์ด ํฌ๊ณ , ์ด๋ก ์ธํด ์ฝ๋์ ๋ฒ๊ทธ๋ฅผ ์๋นํ ์ค์ผ ์ ์๊ฒ ์ฃ .
- ๋ฌผ๋ก , ๋ค์ ์๊ฐํด๋ณธ๋ค๋ฉด, python์ผ๋ก ์ฝ๋ฉํ๋ ๊ฒฝ์ฐ๋ ๋๋ถ๋ถ ๋ฐ์ดํฐ ๋ถ์์ ๋ชฉ์ ์ผ๋ก ํ ๋ ์ด๊ณ , ์ด ๋ ์ฃผ๋ก ์ฌ์ฉํ๋
numpy,pandas๋ฑ์ ๊ฒฝ์ฐ๋ ์ด๋ฏธ dtype๋ค์ด ์ง์ ๋ ์ํ๋ก ์งํ๋์ฃ . ์ด๋ ๊ฒ ์๊ฐํ๋, ๋ ๊ตณ์ด, type์ ์ ์ธํด์ฃผ๋ ๊ฒ ํ์ํ๊ฐ ๋ผ๋ ์๊ฐ์ด ๋ค๊ธฐ๋ ํ๋ค์.
reference
GitHub์์ ์ด ๊ธ์ ๋งํฌ๋ค์ด ์๋ณธ ๋ณด๊ธฐ & ์์ ์ ์src/content/posts/2020-01-23-python_static_typechecking_mypy
๐ ์ฐ๊ด ์ง์ ํ๋ธ:๐ python ์นดํ
๊ณ ๋ฆฌ๐ Python ์ปค๋ฆฌํ๋ผ#python#static-type#type-checking