객체의 유형을 결정 하시겠습니까?


1791

변수가 목록, 사전 또는 다른 항목인지 확인하는 간단한 방법이 있습니까? 유형이 될 수있는 객체를 다시 가져오고 차이를 말할 수 있어야합니다.


44
일반적으로 나는 당신에게 동의하지만, 도움이되는 상황이 있습니다. 이 특별한 경우에 나는 결국 롤백 한 빠른 해킹을하고 있었으므로 이번에는 맞습니다. 그러나 리플렉션을 사용할 때 어떤 경우에는 어떤 유형의 객체를 다루는 지 알아야합니다.
Justin Ethier

67
@ S.Lott 나는 동의하지 않을 것이다; 유형을 알 수 있으면 꽤 변형 된 입력을 처리하고 여전히 올바른 작업을 수행 할 수 있습니다. 순수한 오리 타이핑에 의존하는 고유 한 인터페이스 문제를 해결할 수 있습니다 (예 : Tree의 .bark () 메서드는 Dog와 완전히 다른 의미입니다). 예를 들어, 일부 작업을 수행하는 함수를 만들 수 있습니다 문자열 (예 : 경로), 경로 객체 또는 목록을 허용하는 파일 모두 인터페이스가 다르지만 최종 결과는 동일합니다. 해당 파일에서 일부 작업을 수행하십시오.
Robert P

22
@ S.Lott 나는 그것이 좋은 예라고 생각하기를 바랐다. 그럼에도 불구하고 그것은 오리 타이핑의 주요 실패 지점이며 try도움이되지 않는 지점입니다 . 예를 들어, 사용자가 문자열이나 배열을 전달할 수 있다는 것을 알고 있다면 둘 다 색인 할 수 있지만 해당 색인은 완전히 다른 것을 의미합니다. 이러한 경우에 단순히 try-catch에 의존하면 예기치 않은 이상한 방식으로 실패합니다. 한 가지 해결책은 별도의 방법을 만드는 것이고 다른 하나는 약간의 유형 검사를 추가하는 것입니다. 나는 개인적으로 거의 같은 일을하는 여러 가지 방법보다 다형성 행동을 선호하지만 ... 그건 나 뿐이다 :)
Robert P

22
@ S.Lott, 단위 테스트는 어떻습니까? 때로는 테스트에서 함수가 올바른 유형의 무언가를 리턴하는지 확인하기를 원합니다. 실제 사례는 클래스 팩토리가있는 경우입니다.
Elliot Cameron

17
이해하기 어려운 예제의 경우 serializer / deserializer를 고려하십시오. 정의에 따라 사용자 제공 개체와 직렬화 된 표현간에 변환하고 있습니다. 시리얼 라이저는 전달한 객체의 유형을 결정해야하며 런타임을 요청하지 않고 역 직렬화 된 유형을 결정하기위한 적절한 정보가 없을 수 있습니다. 시스템)!

답변:


1976

객체 유형을 식별하는 데 도움이되는 내장 함수가 두 개 있습니다. 당신은 사용할 수 있습니다 type() 당신은 객체의 정확한 유형을 필요로하는 경우,과 isinstance()확인 무언가에 대한 개체의 유형입니다. 일반적으로 isistance()매우 강력하고 형식 상속도 지원하므로 대부분의 시간 을 사용하려고합니다 .


객체의 실제 유형을 얻으려면 내장 type()함수 를 사용합니다 . 객체를 유일한 매개 변수로 전달하면 해당 객체의 유형 객체가 반환됩니다.

>>> type([]) is list
True
>>> type({}) is dict
True
>>> type('') is str
True
>>> type(0) is int
True

이것은 물론 사용자 정의 유형에도 적용됩니다.

>>> class Test1 (object):
        pass
>>> class Test2 (Test1):
        pass
>>> a = Test1()
>>> b = Test2()
>>> type(a) is Test1
True
>>> type(b) is Test2
True

참고 type()개체 만의 즉각적인 유형을 반환하지만 형의 상속에 대해 얘기 할 수 없습니다.

>>> type(b) is Test1
False

이를 다루려면 isinstance함수를 사용해야합니다 . 이것은 물론 내장 유형에도 적용됩니다.

>>> isinstance(b, Test1)
True
>>> isinstance(b, Test2)
True
>>> isinstance(a, Test1)
True
>>> isinstance(a, Test2)
False
>>> isinstance([], list)
True
>>> isinstance({}, dict)
True

isinstance()파생 된 형식도 허용하므로 개체의 형식을 확인하는 데 일반적으로 선호되는 방법입니다. 따라서 실제로 어떤 이유에서든 유형 객체가 필요하지 않으면를 사용하는 isinstance()것이 좋습니다 type().

의 두 번째 매개 변수는 isinstance()튜플 유형도 허용하므로 여러 유형을 한 번에 확인할 수 있습니다. isinstance그런 다음 객체가 이러한 유형 중 하나 인 경우 true를 반환합니다.

>>> isinstance([], (tuple, list, set))
True

68
유형이 싱글 톤이므로 is대신 사용하는 것이 더 명확하다고 생각합니다.==
John La Rooy

18
@gnibbler의 경우에 당신이 (당신이 시작하는 일을해서는 안되는) 유형 검사되지 않을 것이다 isinstance선호하는 형태는 그래서 둘 다, 어쨌든되어 ==또는 is사용하면된다.
Mike Graham

23
@Mike Graham, type가장 좋은 답변이 있을 때가 있습니다. 경우가 있습니다 isinstance최선의 대답은 오리 입력이 최고의 답변입니다 때가있다. 상황에 더 적합한 것을 선택할 수 있도록 모든 옵션을 아는 것이 중요합니다.
John La Rooy

6
@ gnibbler, 아마도 나 type(foo) is SomeType보다 나은 상황에 부딪치지 않았을 수도 있습니다 isinstance(foo, SomeType).
Mike Graham

5
@poke : 나는 PEP8에 전적으로 동의하지만, 당신은 여기에서 strawman을 공격하고 있습니다 : Sven의 주장의 중요한 부분은 PEP8이 아니었지만 isinstance유스 케이스 (범위 유형 확인)와 함께 사용할 수 있다는 것 입니다. 구문을 정리하면 서브 클래스를 캡처 할 수 있다는 큰 이점이 있습니다. OrderedDict순수한 dicts를 받아들이 기 때문에 코드를 사용하는 사람 이 실패 하는 것을 싫어합니다.
비행 양

165

당신은 그것을 사용하여 할 수 있습니다 type():

>>> a = []
>>> type(a)
<type 'list'>
>>> f = ()
>>> type(f)
<type 'tuple'>

40

try... except블록 을 사용하는 것이 더 Pythonic 일 수 있습니다 . 이렇게하면 목록과 같은 쿼크 클래스 또는 dict와 같은 쿼크 클래스가 있으면 실제로 유형 무엇이든 관계없이 올바르게 작동합니다 .

명확히하기 위해, 변수 유형 사이의 "차이점을 구별하는"선호되는 방법은 덕 타이핑 이라는 것입니다. 되려고. 예를 들어, getattr및로 대괄호 연산자를 오버로드 setattr하지만 재미있는 내부 구성표를 사용 하는 클래스가 있으면 에뮬레이션하려는 경우 사전으로 작동하는 것이 적합합니다.

type(A) is type(B)점검의 또 다른 문제점 A은의 서브 클래스 인 경우 프로그래밍 방식 B으로 원하는 false시점으로 평가 한다는 것입니다 true. 객체가리스트의 서브 클래스 인 경우,리스트처럼 작동해야합니다. 다른 답변에 제시된 유형을 확인하면이를 방지 할 수 있습니다. ( isinstance그러나 작동합니다).


16
오리 타이핑은 실제로 차이점을 말하는 것이 아닙니다. 공통 인터페이스를 사용하는 것입니다.
저스틴에 티어

5
대부분의 코딩 스타일 가이드는 코드의 정상적인 제어 흐름의 일부로 예외 처리를 사용하지 않는 것이 좋습니다. 일반적으로 코드를 읽기가 어렵 기 때문입니다. try... except오류를 처리하고 싶을 때 좋은 솔루션이지만 유형에 따라 동작을 결정할 때는 그렇지 않습니다.
Rens van der Heijden

34

객체의 인스턴스에는 다음이 있습니다.

__class__

속성. 다음은 Python 3.3 콘솔에서 가져온 샘플입니다.

>>> str = "str"
>>> str.__class__
<class 'str'>
>>> i = 2
>>> i.__class__
<class 'int'>
>>> class Test():
...     pass
...
>>> a = Test()
>>> a.__class__
<class '__main__.Test'>

python 3.x 및 New-Style 클래스 (Python 2.6에서 선택적으로 사용 가능)에서 클래스와 유형이 병합되어 예기치 않은 결과가 발생할 수 있습니다. 주로 이런 이유로 종류 / 클래스를 테스트 나의 마음에 드는 방법은이다 isinstance 기능이 내장되어 있습니다.


2
끝에 당신의 요점은 매우 중요합니다. type (obj) is Class가 올바르게 작동하지 않았지만 isinstance가 트릭을 수행했습니다. 어쨌든 isinstance가 선호된다는 것을 이해하지만 받아 들인 대답에서 제안 된 것처럼 파생 된 유형을 확인하는 것보다 유리합니다.
mstbaum

__class__파이썬 2.x에서는 대부분 괜찮습니다. 파이썬에서 __class__속성이 없는 유일한 객체 는 구식 클래스 AFAIK입니다. 그건 그렇고 파이썬 3의 관심사를 이해하지 못합니다-그런 버전에서는 모든 객체 __class__에 적절한 클래스를 가리키는 속성이 있습니다.
Alan Franzoni

21

파이썬 객체의 타입 결정

객체의 유형 결정 type

>>> obj = object()
>>> type(obj)
<class 'object'>

그것이 작동하지만, 이중 밑줄 속성 __class__은 피상적으로 공개적이지 않으며, 아마도이 경우에는 아니지만 내장 함수는 일반적으로 더 나은 동작을합니다.

>>> obj.__class__ # avoid this!
<class 'object'>

타입 검사

변수가 목록, 사전 또는 다른 항목인지 확인하는 간단한 방법이 있습니까? 유형이 될 수있는 객체를 다시 가져오고 차이를 말할 수 있어야합니다.

글쎄, 그것은 다른 질문입니다, type-use를 사용하지 마십시오 isinstance:

def foo(obj):
    """given a string with items separated by spaces, 
    or a list or tuple, 
    do something sensible
    """
    if isinstance(obj, str):
        obj = str.split()
    return _foo_handles_only_lists_or_tuples(obj)

여기에는 strLiskov Substitution의 원칙에 따라 사용자가 코드를 어 기지 않고 서브 클래스 인스턴스를 사용할 수 있기를 원하는 서브 클래 싱으로 사용자가 영리하거나 현명한 작업을 수행하는 경우가 포함됩니다 isinstance.

추상화 사용

더 좋은 점은 collections또는 numbers다음 에서 특정 추상 기본 클래스를 찾을 수 있습니다 .

from collections import Iterable
from numbers import Number

def bar(obj):
    """does something sensible with an iterable of numbers, 
    or just one number
    """
    if isinstance(obj, Number): # make it a 1-tuple
        obj = (obj,)
    if not isinstance(obj, Iterable):
        raise TypeError('obj must be either a number or iterable of numbers')
    return _bar_sensible_with_iterable(obj)

또는 명시 적으로 유형 검사하지 마십시오

또는 아마도 무엇보다도 오리 타이핑을 사용하고 코드를 명시 적으로 유형 검사하지 마십시오. 오리 타이핑은 Liskov 대체를 더 우아하고 덜 장황하게 지원합니다.

def baz(obj):
    """given an obj, a dict (or anything with an .items method) 
    do something sensible with each key-value pair
    """
    for key, value in obj.items():
        _baz_something_sensible(key, value)

결론

  • type실제로 인스턴스 클래스를 얻는 데 사용 합니다.
  • isinstance실제 서브 클래스 또는 등록 된 추상화를 명시 적으로 확인하는 데 사용 합니다.
  • 그리고 적절한 곳에서 유형 검사를 피하십시오.

명시 적으로 확인하는 대신 항상 try/ 가 있습니다 except.
toonarmycaptain

아마도 사용자가 전달할 유형에 대해 잘 모르면 사용자가 할 일입니다. 예외와 관련이없는 경우가 아니라면 예외 처리로 올바른 구현을 어수선하게 만들고 싶지 않습니다. 예외 사항은 사용자에게 사용법을 수정해야 함을 알리기에 충분해야합니다.
Aaron Hall

13

당신은 사용할 수 있습니다 type()또는 isinstance().

>>> type([]) is list
True

list동일한 이름의 현재 범위에서 변수를 할당하여 클로버 또는 다른 유형을 경고 할 수 있습니다 .

>>> the_d = {}
>>> t = lambda x: "aight" if type(x) is dict else "NOPE"
>>> t(the_d) 'aight'
>>> dict = "dude."
>>> t(the_d) 'NOPE'

위에서 우리 dict는 문자열에 다시 할당되는 것을 보았습니다 .

type({}) is dict

... 실패.

이 문제를 해결하고 type()보다 신중하게 사용하려면 :

>>> import __builtin__
>>> the_d = {}
>>> type({}) is dict
True
>>> dict =""
>>> type({}) is dict
False
>>> type({}) is __builtin__.dict
True

2
내장 데이터 형식의 이름을 섀도 잉하는 것이이 경우에 좋지 않다는 것을 지적 할 필요가 없습니다. 귀하의 dict문자열은 같은, 다른 코드의 많은 실패합니다 dict([("key1", "value1"), ("key2", "value2")]). 이런 종류의 문제에 대한 답은 "그런데 그렇게하지 마십시오" 입니다. 내장 유형 이름을 숨기지 말고 제대로 작동 할 것으로 예상하십시오.
Blckknght

3
"하지 마십시오"부분에 동의합니다. 그러나 실제로 누군가에게 당신이 적어도 왜 안되는지 설명하지 말라고 말하면 이것이 그렇게 할 수있는 적절한 기회라고 생각했습니다. 나는 신중한 방법으로 추악하게 보이고 왜 그들이 원하지 않는지 설명하고 결정하게했습니다.
deed02392 2016 년

클래식 인스턴스의 경우 Python 2.x에서 type ()이 예상대로 작동하지 않습니다.
Alan Franzoni

5

질문이 꽤 오래되었지만 적절한 방법을 찾아 내면서이 문제를 우연히 발견 했으며 적어도 Python 2.x (Python 3에서는 확인하지 않았지만 고전적인 클래스에서 문제가 발생했기 때문에 여전히 명확해야 함) 그런 버전에서 사라지면 아마 중요하지 않을 것입니다).

여기서 제목의 질문에 대답하려고합니다 . 임의의 객체 유형을 어떻게 결정할 수 있습니까? isinstance를 사용하거나 사용하지 않는 것에 대한 다른 제안은 많은 의견과 답변에서 훌륭하지만 이러한 문제는 다루지 않습니다.

type()접근 방식 의 주요 문제 는 이전 스타일 인스턴스에서 제대로 작동하지 않는다는 것입니다 .

class One:
    pass

class Two:
    pass


o = One()
t = Two()

o_type = type(o)
t_type = type(t)

print "Are o and t instances of the same class?", o_type is t_type

이 스 니펫을 실행하면 다음이 생성됩니다.

Are o and t instances of the same class? True

나는 대부분의 사람들이 기대하는 것이 아니라고 주장한다.

__class__접근 방식은 정확성에 가장 가까운,하지만 하나의 중요한 경우에없는 일이됩니다 옛날 스타일의 전달 된 객체 인 경우 클래스 (!하지 인스턴스), 이러한 개체는 속성이 부족하기 때문이다.

이것은 내가 생각할 수있는 가장 작은 코드 스 니펫으로 일관성있는 질문을 일관된 방식으로 충족시킵니다.

#!/usr/bin/env python
from types import ClassType
#we adopt the null object pattern in the (unlikely) case
#that __class__ is None for some strange reason
_NO_CLASS=object()
def get_object_type(obj):
    obj_type = getattr(obj, "__class__", _NO_CLASS)
    if obj_type is not _NO_CLASS:
        return obj_type
    # AFAIK the only situation where this happens is an old-style class
    obj_type = type(obj)
    if obj_type is not ClassType:
        raise ValueError("Could not determine object '{}' type.".format(obj_type))
    return obj_type

5

isinstance 사용에주의

isinstance(True, bool)
True
>>> isinstance(True, int)
True

그러나 유형

type(True) == bool
True
>>> type(True) == int
False

3

이전 답변 외에, collections.abc오리 타이핑을 보완하는 몇 가지 추상 기본 클래스 (ABC)가 포함되어 있음을 언급하는 것이 좋습니다.

예를 들어, 다음과 같은 목록이 있는지 명시 적으로 확인하는 대신 :

isinstance(my_obj, list)

당신이 가지고있는 객체가 아이템을 얻는 것을 허용하는 것에 만 관심이 있다면, 다음을 사용할 수 있습니다 collections.abc.Sequence:

from collections.abc import Sequence
isinstance(my_obj, Sequence) 

항목 (예 : 가변 시퀀스)을 가져오고 설정 하고 삭제할 수있는 객체에 관심이있는 경우을 선택합니다 collections.abc.MutableSequence.

다른 많은 상식이있다 정의 Mapping맵으로 사용할 수 있습니다 개체에 대한 Iterable, Callable등등. 이들에 대한 전체 목록은에 대한 설명서를 참조하십시오 collections.abc.


1

일반적으로 클래스 이름을 가진 객체에서 문자열을 추출 할 수 있습니다.

str_class = object.__class__.__name__

비교를 위해 사용합니다.

if str_class == 'dict':
    # blablabla..
elif str_class == 'customclass':
    # blebleble..

1

대신 사용하여 많은 실용적인 경우 type또는 isinstance사용자가 사용할 수도 @functools.singledispatch정의하는 데 사용되는 일반적인 기능 ( 이종 동일한 동작을 구현하는 다양한 기능 이루어지는 기능 ).

즉, 다음과 같은 코드가있을 때이를 사용하려고합니다.

def do_something(arg):
    if isinstance(arg, int):
        ... # some code specific to processing integers
    if isinstance(arg, str):
        ... # some code specific to processing strings
    if isinstance(arg, list):
        ... # some code specific to processing lists
    ...  # etc

작동 방식의 작은 예는 다음과 같습니다.

from functools import singledispatch


@singledispatch
def say_type(arg):
    raise NotImplementedError(f"I don't work with {type(arg)}")


@say_type.register
def _(arg: int):
    print(f"{arg} is an integer")


@say_type.register
def _(arg: bool):
    print(f"{arg} is a boolean")
>>> say_type(0)
0 is an integer
>>> say_type(False)
False is a boolean
>>> say_type(dict())
# long error traceback ending with:
NotImplementedError: I don't work with <class 'dict'>

또한 추상 클래스 를 사용 하여 여러 유형을 한 번에 다룰 수 있습니다.

from collections.abc import Sequence


@say_type.register
def _(arg: Sequence):
    print(f"{arg} is a sequence!")
>>> say_type([0, 1, 2])
[0, 1, 2] is a sequence!
>>> say_type((1, 2, 3))
(1, 2, 3) is a sequence!

0

type()보다 나은 솔루션 isinstance(), 특히booleans 다음 .

True그리고 False단지 키워드 평균이 있습니다 10파이썬. 그러므로,

isinstance(True, int)

isinstance(False, int)

둘 다 반환 True합니다. 두 부울은 정수의 인스턴스입니다. type()그러나 더 영리합니다.

type(True) == int

을 반환합니다 False.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.