계기
강타입언어에 익숙해있다보니 파이썬을 하면서 보이는 any는 상당히 불편했다. 타입힌트를 사용하지만 간혹 라이브러리에서 unknown, any로 확인되는 것들을 놓치다보면 여전히 any는 자주 등장했다. any도 그렇지만 문제는 라이브러리의 잘못된 타입힌트가 간혹 있는데, 이 타입힌트를 바꿔주지 않으면 오류로 잡히니 답답했다.
단적인 예시로, Tensor를 Image로 잡혀 있어 image.size로 구현하다가 에러가 있어 디버깅해보니 애초에 image타입이 아니였던 것이다.... 그런데 라이브러리에서 리턴하는 타입이다보니 변경을 하려면 방법이 필요해서 함수를 구현하게 되었다.
1. 타입체킹
vsc 자체적으로 파이썬의 타입체킹을 설정해주었다.
cmd , 통해서 설정을 열고 type check 검색, Python > Analysis: Type Checking Mode에서 원하는 모드를 선택해주는데, 처음부터 잘 세팅한건 아닌지라,, standard로 두었다. strict로 하니 오류가 2배로 변한다.... ㅎㅎㅎ
2. 코드 구현
from typing import Any, Type, TypeVar, Union, Tuple
T = TypeVar('T')
def type_hint(value: Any, expected_type: Union[Type[T], Tuple[Type[T], ...]]) -> T:
"""Check if the object is an instance of the given class(es) and raise TypeError if not."""
# if not isinstance(value, expected_type):
# # ex가 튜플인지 확인
# if isinstance(expected_type, tuple):
# expected_types = ', '.join(c.__name__ for c in expected_type) # 각 타입의 __name__ 속성 가져오기
# raise TypeError(f"Expected instance of one of {expected_types}, but got {type(value).__name__}")
# else:
# raise TypeError(f"Expected instance of {expected_type.__name__}, but got {type(value).__name__}")
return value
간단한 함수다. 첫 번째 매개변수에는 타입힌트를 변경할 값을, 두 번째에는 변경할 타입을 넣어준다. 그리고 두 번째 매개변수에 넣어준 타입을 제네릭을 통해 리턴해서 타입을 맞춰준다.
안에 주석을 처리한건, isinstance를 통해 실제로 타입을 검증할 수 있도록 했고, 맞지 않으면 TypeError를 반환하도록 했는데, 기존 타입힌트에 대한 테스트코드라서 기존 타입힌트에 대한 검증을 위한 기능이다.
3. 사용
# 데이터 로더 생성
train_loader, val_loader = get_data_loaders(data_dir, batch_size)
train_dataset = type_hint(train_loader.dataset, Subset[KeySignatureDataset])
val_dataset = type_hint(val_loader.dataset, Subset[KeySignatureDataset])
# 데이터셋의 길이를 출력
print(f"학습 데이터: {len(train_dataset)}개, 검증 데이터: {len(val_dataset)}개")
이런 함수를 구현했을 때, train_loader에는 DataLoader 를 타입힌트로 지정되어 있고 그 안에 train_loader.dataset이라는 값을 확인해보면 Dataset이 지정되어 있다. 하지만, 실제로 디버깅해보면 <torch.utils.data.dataset.Subset object at 0x123291160> 이렇게 확인되고 있고 즉, 프로퍼티에는 Subnet이 속해 있음을 알 수 있다.
train_dataset이 실제로 dataset이라면 len으로 길이를 확인할 수 없는데, 파이썬은 타입에러를 걸러내지 않으므로 dataset으로 타입이 지정되어있지만 정상적으로 숫자를 반환한다는 것은 dataset이라고 지정되어있지만 실제로는 다른 타입이라고 판단했고, len없이 _dataset 자체가 Subnet임을 파악하고 구현한 type_hint로 Subnet으로 변경해준 모습이다.
이렇게 타입힌트를 변경해주고 나면 타입체킹에서도 len 등 이상이 생기지 않는다.
다른 예시




transform은 Compose라는 torchvision의 클래스인데, image를 넣었을 때 Image로 반환한다고 인식하는 것 같다. 그래서 unsqueeze() 메서드를 사용할 수 없다고 한다. (torch.Tensor의 메서드이기 때문에)
그래서 구현한 type_hint를 사용하면? 사용할 수 있게 된다.
4. 코멘트
너무너무 별거 아닌 함수지만 파이썬을 최근에 계속 다루면서 그렇게 정교한 라이브러리가 많은데도 타입힌트를 변경하는 이런 간단한 라이브러리가 내가 못찾은건지 아무튼 쉽지 않았는데, 파이썬과 파이썬을 사용하는 그 철학을 조금씩 이해하고 나면 적응하겠지만 중요한 것은 나의 의도대로 코딩을 하고 있는지 정확한 인지가 필요한 것 같다. 사실 컴퓨터만큼 휴먼이슈 없이 100% 정확하다면 타입이고 뭐고 에러도 없겠지만 그럴리가 없고 그 것을 떠나서 100% 정확하다는 확신이 없으니까 타입체킹은 중요한 것 같다.
'개발 > language' 카테고리의 다른 글
| [JS] 파일 업로드 클릭시 반응이 없을 때.. feat.chrome (0) | 2023.12.02 |
|---|---|
| [JavaScript] const로 할당한 값이 바뀌는 이유 (0) | 2023.09.10 |
| [JavaScript] Date객체 String 타입변환에 따른 결과 (0) | 2023.09.09 |
| [TypeScript]타입 할당 ?, !의 차이에 대한 실제 사례 feat.JWT (0) | 2023.08.04 |