Python / type() / 데이터 타입(자료형) 확인하는 함수

Python의 type(value)는 값이 속한 실제 타입 객체를 반환합니다. 결과는 "int" 같은 문자열이 아니며, 정확히 같은 타입인지 확인하려면 type(value) is int처럼 비교합니다. 하위 클래스까지 허용하는 일반적인 타입 검사는 isinstance()가 더 적합합니다.

type()의 기본 사용법과 반환값

type()에 인수 하나를 전달하면 그 객체의 타입을 얻습니다. Python에서는 숫자·문자열·컬렉션뿐 아니라 타입 자체도 객체입니다. 대화형 셸은 식의 결과를 보여 주지만 파일로 실행하는 프로그램에서는 print() 등으로 결과를 표시해야 합니다.

아래 예제는 Python 3.12에서 실행할 수 있습니다. 전체 코드를 UTF-8의 type_example.py로 저장하고 python type_example.py로 실행합니다. 환경에 따라 python3을 사용하며 각 예제는 파일 내용을 교체해 독립적으로 실행할 수 있습니다.

values = (123, 12.3, "abc", [1, 2], (1, 2), {"a": 1}, {1, 2}, 1 + 2j, True, None)
for value in values:
    print(type(value))

예상 결과:

<class 'int'>
<class 'float'>
<class 'str'>
<class 'list'>
<class 'tuple'>
<class 'dict'>
<class 'set'>
<class 'complex'>
<class 'bool'>
<class 'NoneType'>

<class 'int'>는 정수 타입을 나타내는 객체의 표시입니다. 표시된 문구를 문자열과 비교하면 타입 검사가 되지 않습니다. __name__은 사람이 읽을 이름이 필요할 때 사용할 수 있지만, 이름이 같은 서로 다른 클래스도 있으므로 판정 기준은 타입 객체로 잡습니다.

kind = type(123)
print(kind is int)
print(kind == "int")
print(kind.__name__)
True
False
int

type(name, bases, dict)처럼 세 인수를 받는 형태는 새 클래스를 만드는 별도 용도입니다. 단순히 자료형을 확인할 때는 인수 하나를 사용하는 형식과 구분합니다.

정확한 타입 비교와 isinstance()의 차이

type(value) is T는 실제 타입이 T 그 자체인지 확인합니다. isinstance(value, T)는 해당 타입과 그 하위 클래스도 허용하므로 상속을 사용하는 코드에서 유용합니다. 다음은 Animal을 상속한 Dog와 숫자 타입을 비교하는 전체 예제입니다.

class Animal:
    pass

class Dog(Animal):
    pass

pet = Dog()
print(type(pet).__name__)
print(type(pet) is Animal)
print(isinstance(pet, Animal))
print(type(True) is int)
print(isinstance(True, int))
print(isinstance(3, (int, float)))
Dog
False
True
False
True
True

Dog 객체의 실제 타입은 Dog이므로 Animal과 정확히 같지는 않지만 Animal의 인스턴스로 인정됩니다. 또한 bool은 int의 하위 클래스이므로 isinstance(True, int)는 참입니다. 논리값을 수량으로 허용하지 않으려면 정확히 int인지 확인하거나 bool을 별도로 제외해야 합니다. 여러 타입을 허용할 때는 예제처럼 타입의 튜플을 전달할 수 있습니다.

변수에 다른 타입을 재대입하면

Python 객체와 타입을 이해할 때는 변수 이름이 현재 어떤 객체를 가리키는지 구분해야 합니다. 같은 이름에 문자열을 대입할 수 있다는 사실이 이전 정수 객체의 타입을 문자열로 바꾼다는 뜻은 아닙니다.

value = 123
original = value
print(type(value).__name__)
value = "123"
print(type(value).__name__)
print(type(original).__name__)
int
str
int

처음 두 이름은 같은 정수 값을 가리킵니다. value = "123" 이후 value는 문자열을, original은 이전 정수를 가리킵니다. 이 재대입은 int()나 str()로 값을 변환하는 작업과 구분합니다.

리스트의 타입과 내용, 타입 힌트는 다릅니다

type(values)는 리스트 안의 모든 원소가 같은 타입인지 검사하지 않습니다. list[int] 같은 타입 힌트도 Python 실행기가 자동으로 원소를 검증하거나 변환하게 만드는 명령은 아닙니다.

values: list[int] = [1, "2"]
print(type(values).__name__)
print(all(type(item) is int for item in values))
try:
    print(isinstance(values, list[int]))
except TypeError:
    print("TypeError")
list
False
TypeError

힌트에 int를 적었어도 문자열 "2"가 들어간 리스트는 실행 중에 만들어질 수 있습니다. 예제에서는 원소별 정확한 int 검사가 거짓이며, isinstance()의 두 번째 인수로 list[int]를 전달하면 TypeError가 발생합니다. 컨테이너 타입과 내부 스키마 검사를 분리하고, 정적 타입 검사기의 경고도 함께 활용합니다.

None과 실제 값의 조건까지 확인하기

None은 값이 없음을 나타내는 별도 객체이며 value is None으로 확인하는 것이 명확합니다. 타입을 통과해도 업무 조건을 만족하는지는 별도로 판단해야 합니다. 다음은 bool을 제외한 정수 중 0 이상만 허용합니다.

value = None
print(value is None)
print(type(value).__name__)

def valid_count(value):
    return type(value) is int and value >= 0

for value in (3, -1, True, "3", None):
    print(repr(value), valid_count(value))
True
NoneType
3 True
-1 False
True False
'3' False
None False

and는 앞의 타입 검사가 거짓이면 뒤의 비교를 실행하지 않아 문자열이나 None에 >= 0을 적용하지 않습니다. 반면 -1은 정수이지만 값 조건에서 거부됩니다. 입력을 실제 정수로 변환할 것인지, 특정 타입만 받을 것인지 정책을 먼저 정하고 범위·누락값·형식 조건을 추가합니다.