조금씩 꾸준히 완성을 향해

[Python] Typing & Type hint /다양한 타입 힌트 사용법 본문

Python/문법

[Python] Typing & Type hint /다양한 타입 힌트 사용법

all_sound 2022. 9. 29. 16:58

python에서 typing 할 때 사용 가능한 여러가지 방법들을 소개한다.

(타입 힌트의 개념이나 타입 체크에 관한 기본 내용은 이전 포스팅을 참고 바람)

Callable Type

함수 자체를 인자로 넘겨줄 때 사용한다. 

from typing import Callable   # 타이핑 모듈의 callable 객체 import

def add_sub(a: int, b: int) -> list:
    return [a + b, a - b]

# 함수를 인자로 넘겨줄 때 callable 사용
def add_sub_new(func: Callable[[int, int], list]) ->list:
    return func(2, 3)
    
print(add_sub_new(add_sub))  # [5, -1]

▶ Callable[[a, b], c]

 여기서 첫번째 대괄호의 a, b는 함수 안에 들어가는 인자들의 타입이고, c는 리턴값의 타입이다. 

def test():
    pass

print(add_sub_new(test))

만약에 이렇게 Callable type이 지켜지지 않은 함수가 들어왔을 때, 타입체킹을 해 보면 에러가 뜨는 걸 볼 수 있다. 

(mypy, pyright 사용법은 이전 포스팅 참고)

 

 

Class type

클래스 자체를 타입으로 사용하는 방법이다. 

class Hello:
    def returnNum(self) -> int:
        return 7

class World:
    def returnNum(self) -> int:
        return 70

먼저 이렇게 클래스들을 정의하고 타입을 지정해 준다.

hello: Hello = Hello() 
world: World = World()

그리고 이렇게 인스턴스의 타입으로는 클래스 자체를 지정한다.

def findNum(ins: Hello) -> int:
    return ins.returnNum()

인스턴스를 받아 메소드를 리턴하는 함수를 새롭게 만들고 호출을 하는데,

이 함수의 인스턴스로는 Hello 클래스만이 들어올 수 있도록 설정한다. 

print(findNum(hello))  #7
print(findNum(world))  #70

그리고 이 출력들을 타입 체킹하면 두번째 world를 받은 함수에서 에러가 나는 것을 확인할 수 있다. 

 

 

참고로 클래스 타입을 사용할 때 따옴표를 넣어 표시하기도 한다. (버전에 따라 방식이 다를 수 있으니 확인 필요)

hello: 'Hello' = Hello()

 

 

Union Type

Union은 사용 가능한 타입들의 집합을 말한다. 즉, 한 변수에 여러 종류의 타입을 지정할 때 사용가능하다. 

from typing import Union  #typing 모듈에서 Union 객체 import

a: Union[int, str] = 3  # 변수 a는 int 혹은 str 타입어야 한다.
a = "hello"

def func(x: Union[int, str]) -> Union[int, str]:
    return x

print(func(a)) #hello

여기서 a에는 정수타입이 들어올 수도 있고 문자열 타입이 들어올 수도 있다. 

 

 

Optional type

optional은 해당 타입이 있을 수도 있고 없을 수도 있는, 말그대로 옵션의 상황에서 사용할 수 있다.

union과 개념이 비슷해서 호환도 가능하다. 

from typing import Optional  #typing 모듈에서 Optional 객체 import

def nameCheck(name: str) -> Optional[str]:  
    if name == "Dasol":
        return 'correct'
    else:
        return None

x: Optional[str] = nameCheck('Dasol')

print(x)

nameCheck 함수의 return 타입에 Optional[str]이 들어와 있다. 이는 return 값이 문자열 타입으로 들어올 수도 있고, return 값이 없을 수도 있다는 의미이다. 함수 안에  return 조건이 문자열 혹은 None으로 짜져있는 걸 확인할 수 있다.

 

타입 체크해 보면 당연히 오류없이 통과된다. 

 

이를 아래와 같이 Union type으로 바꿀 수도 있다.

Union[str, None]

 

 

Final type

변하지 않는 상수를 지정할 때 쓰이는 타입이다.

from typing_extensions import Final  

NAME: Final = "Daosl"

이렇게  한 번 지정되면 NAME이란 변수의 값을 변경할 수 없다.

NAME = 'Minji'

print(NAME)

만약 이렇게 변경을 시도한 후, 타입 체크를 하면 에러가 뜨는 걸 볼 수 있다. 

 

 

Type alias 

타입에 변수처럼 별칭을 지정해서 사용하는 것을 말한다. 코드의 재사용성을 높일 수 있다.

X = int
x: X = 8
from typing import Union, List, Tuple, Dict, Optional

Value = Union[
    int, bool, Union[List[str], List[int], Tuple[int, ...]], Optional[Dict[str, float]]
]  # 타입을 변수처럼 사용 -> 코드 간결화

value: Value = 17

def cal(v: Value) -> Value:
    return v

 

※ Dictionary alias

딕셔너리에서 key와 value 값 각각에 타입을 지정하는 방식!

typing_extensions 모듈에서 TypedDict 객체를 import 해서 사용할 수 있다. 

from typing_extensions import TypedDict

class Person(TypedDict):
    name: str
    age: int
    height: float
    isSingle: bool

person: Person = {"name": 'Dasol', "age": 28, "height": 160.8, "isSingle": True}

이런식으로 TypedDict객체를 이용해 클래스를 만들어 각 item들의 타입을 지정해 준다. 변수 옆에 붙이는 일괄적인 타입 힌트 보다 훨씬 자유도가 높고 독립적인 딕셔너리를 생성할 수 있다.