type ()과 isinstance ()의 차이점은 무엇입니까?


1247

이 두 코드 조각의 차이점은 무엇입니까?

사용 type():

import types

if type(a) is types.DictType:
    do_something()
if type(b) in types.StringTypes:
    do_something_else()

사용 isinstance():

if isinstance(a, dict):
    do_something()
if isinstance(b, str) or isinstance(b, unicode):
    do_something_else()

참고 : 그렇지 않은 경우 strunicode(그냥 확인할 수있는 곳 basestring), 여러 유형에 대해 확인하기 위해 튜플을 사용할 수 있습니다. 있는지 확인하려면 somethingIS int또는 str사용 isinstance(something, (int, str)).
xuiqzy

답변:


1270

다른 (이미 좋은!) 답변의 내용을 요약하면 isinstance상속을 제공하고 (파생 클래스 인스턴스도 기본 클래스 인스턴스입니다) 동일성을 검사 type하지 않고 (유형의 ID를 요구하고 인스턴스를 거부합니다) 하위 유형, AKA 하위 클래스).

일반적으로 파이썬에서는 코드가 상속을 지원하기를 원합니다 (물론 상속이 너무 편리하기 때문에 코드를 사용하여 코드를 사용하는 것을 중지하는 것이 좋지 않습니다!). 그래서 완벽하게 지원하기 때문에 s의 isinstanceID를 확인하는 것보다 나쁘지 않습니다. type계승.

그것은하지 그입니다 isinstance입니다 좋은 당신을 - 그것은 마음 그냥 덜 나쁜 종류의 평등을 확인하는 것보다. 인수를 사용해보십시오 : 정상, 파이썬, 선호하는 솔루션은 거의 예외없이 "오리 입력"입니다 것처럼 그것은에서 할, 그것은 특정 원하는 형식이었다 try/ except인수가 그 사실 아닌 경우 발생할 수있는 모든 예외를 잡는 문 유형 (또는 다른 유형은 멋지게 오리 모방 ;-)하고 except절에서 다른 것을 시도하십시오 ( "아마"인 다른 유형의 인수를 사용하여).

basestring 있다 , 그러나, 존재하는 아주 특별한 경우-A 내장 타입 만이 사용하도록하려면 isinstance(모두 strunicode서브 클래스 basestring). 문자열은 시퀀스 (반복, 색인, 슬라이스 등) 일 수 있지만 일반적으로 문자열을 "스칼라"유형으로 취급하려고합니다. 모든 종류의 문자열을 처리하기에는 다소 불편합니다 (합리적으로 빈번한 사용 사례). 문자열 (그리고 아마도 다른 스칼라 타입, 즉 당신이 반복 할 수없는 타입), 다른 방법으로 모든 컨테이너 (목록, 세트, ​​dicts ... ...)를 추가하고 basestring플러스 isinstance-전체 구조 관용구는 다음과 같습니다.

if isinstance(x, basestring)
  return treatasscalar(x)
try:
  return treatasiter(iter(x))
except TypeError:
  return treatasscalar(x)

basestring이를 추상 기본 클래스 ( "ABC") 라고 말할 수 있습니다. 서브 클래스에 구체적인 기능을 제공하지 않고 주로와 함께 사용하기위한 "마커"로 존재합니다 isinstance. 파이썬에서 개념이 일반화되고있는 PEP 3119 가 채택되어 파이썬 2.6 및 3.0부터 구현 되었으므로이 개념은 분명히 파이썬에서 성장 하고 있습니다.

PEP는 ABC가 종종 오리 타이핑을 대신 할 수 있지만 일반적으로 그렇게해야한다는 큰 압력이 없음을 분명히합니다 ( 여기 참조 ). 그러나 최근 파이썬 버전에서 구현 된 ABC는 추가적인 장점을 제공합니다. isinstance(그리고 issubclass)는 이제 "[파생 클래스의 인스턴스" "이상의 의미를 가질 수 있습니다 (특히 모든 클래스는 ABC에"등록 "될 수 있음) 서브 클래스로 표시하고 해당 인스턴스를 ABC의 인스턴스로 표시). ABC는 또한 템플릿 메소드 디자인 패턴 응용 프로그램을 통해 매우 자연스러운 방식으로 실제 서브 클래스에 추가적인 편의성을 제공 할 수 있습니다 ( AB와 독립적으로 TM DP에 대한 자세한 내용은 여기여기 [[파트 II] 참조). .

Python 2.6에서 제공되는 ABC 지원의 기본 메커니즘은 여기를 참조 하십시오 . 3.1 버전은 매우 유사하며 여기를 참조 하십시오 . 두 버전 모두 표준 라이브러리 모듈 모음 (3.1 버전) (매우 유사한 2.6 버전의 경우 여기 참조 )은 몇 가지 유용한 ABC를 제공합니다.

이 답변의 목적을 위해, 키 것은 (예 : 믹스 인 클래스의 고전 파이썬 대안에 비해 TM DP 기능에 대한 틀림없이 더 자연스럽게 배치, 넘어 상식에 대해 유지하는 UserDict.DictMixin ) 그들이 만드는 것입니다 isinstance(과 issubclass) 훨씬 더 매력적이고 널리 사용되는 (Python 2.6 이상) (2.5 이전 및 이전 버전), 이에 비해 최근의 Python 버전에서는 이전보다 이전에 유형 평등을 검사하는 것이 훨씬 더 나쁜 방법이되었습니다.


9
'인스턴스가 좋지 않다는 것은 아닙니다. 여러분의 유형이 같은지 확인하는 것보다 덜 나쁩니다. 파이썬에서 선호하는 일반적인 해결책은 거의 "덕 타이핑"입니다. 이것은 다소 제한된 관점입니다. 예를 들어, 유형이 문법을 반영하는 인터프리터에서 isinstance ()를 사용하는 경우 가 매우 좋습니다. "Pythonic"인 것이 전부는 아닙니다!
Gene Callahan

2
basestring 파이썬 3에 사용할 수 없습니다
erobertc

@GeneCallahan은 매우 좋은 사례가 있기 때문에, 일반적인 규칙이 아니라고 말한 것은 아닙니다. 사전에 유형을 확인하는 것이 확실히 가능하지만 오리를 흔드는 것은 대부분의 경우를보다 유연하고 효율적으로 처리 해야한다는 데 동의합니다 .
Eric Ed Lohmar

@erobertc, Python 3.0의 새로운 기능에 따르면 "내장 된 기본 문자열 추상 형식이 제거되었습니다. 대신 str을 사용하십시오."
neurite

344

다음 은 불가능한 isinstance것을 달성 하는 예입니다 type.

class Vehicle:
    pass

class Truck(Vehicle):
    pass

이 경우 트럭 오브젝트는 Vehicle이지만 다음과 같은 결과를 얻습니다.

isinstance(Vehicle(), Vehicle)  # returns True
type(Vehicle()) == Vehicle      # returns True
isinstance(Truck(), Vehicle)    # returns True
type(Truck()) == Vehicle        # returns False, and this probably won't be what you want.

다시 말해, isinstance서브 클래스에서도 마찬가지입니다.

파이썬에서 객체의 유형을 비교하는 방법을 참조하십시오.


143
isInstance 동작을 원하지 않는 경우가 있기 때문에 "더 나은"것은 없다고 주장합니다. 그들은 단지 다른 것을합니다.
philgo20

27
-1, "인스턴스가 유형보다 낫다"는 잘못된 주석입니다. 처음에는 " type더 이상 사용되지 않으며 isinstance대신 사용 "하는 것으로 이해 됩니다. 예를 들어, 내가 원하는 것은 정확히 type()확인하는 것이었지만 그 이유로 짧은 시간 동안 잘못 (그리고 약간 디버깅해야했습니다).
ceremcem

8
그것들이 어떻게 다르게 작동하는지에 대한 좋은 예이지만, 나는 특별히 필요 type()하지 않은 경우에 부딪쳤다 isinstance(). 하나는 좋지 않습니다. 그들은 다른 것들을위한 것입니다.
EL_DON

103

파이썬 isinstance()과 차이점은 type()무엇입니까?

형식 검사

isinstance(obj, Base)

서브 클래스 및 여러 가능한 기본 인스턴스를 허용합니다.

isinstance(obj, (Base1, Base2))

반면에 형식 검사

type(obj) is Base

참조 된 유형 만 지원합니다.


(!) 참고로, is보다 가능성이 더 적합

type(obj) == Base

클래스는 싱글 톤이기 때문입니다.

유형 검사 피하기-다형성 사용 (덕 타이핑)

Python에서는 일반적으로 인수에 모든 유형을 허용하고 예상대로 처리하며 객체가 예상대로 작동하지 않으면 적절한 오류가 발생합니다. 이것은 다형성으로 알려져 있으며 오리 타이핑이라고도합니다.

def function_of_duck(duck):
    duck.quack()
    duck.swim()

위의 코드가 작동하면 논쟁은 오리라고 가정 할 수 있습니다. 따라서 오리의 실제 하위 유형 인 다른 것들을 전달할 수 있습니다.

function_of_duck(mallard)

또는 오리처럼 작동합니다.

function_of_duck(object_that_quacks_and_swims_like_a_duck)

우리 코드는 여전히 작동합니다.

그러나 명시 적으로 유형을 확인하는 것이 바람직한 경우가 있습니다. 아마도 다른 객체 유형과 관련이있는 현명한 일이있을 것입니다. 예를 들어 Pandas Dataframe 객체는 dicts 또는 레코드 . 이 경우 코드에서 올바르게 처리 할 수 ​​있도록 인수 유형을 알아야합니다.

따라서 질문에 대답하려면 다음을 수행하십시오.

파이썬 isinstance()과 차이점은 type()무엇입니까?

차이점을 보여줄 수 있습니다.

type

함수가 특정 종류의 인수 (생성자의 일반적인 사용 사례)를 얻는 경우 특정 동작을 보장해야한다고 가정하십시오. 다음과 같은 유형을 확인하면

def foo(data):
    '''accepts a dict to construct something, string support in future'''
    if type(data) is not dict:
        # we're only going to test for dicts for now
        raise ValueError('only dicts are supported for now')

dict(우리가 코드가 Liskov Substitution 의 원칙을 따를 것으로 기대한다면 , 서브 타입이 타입으로 대체 될 수 있음) 서브 클래스 인 dict을 전달하려고 하면 코드가 깨집니다! :

from collections import OrderedDict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

오류가 발생합니다!

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in foo
ValueError: argument must be a dict

isinstance

그러나를 사용하면 isinstanceLiskov 대체를 지원할 수 있습니다! :

def foo(a_dict):
    if not isinstance(a_dict, dict):
        raise ValueError('argument must be a dict')
    return a_dict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

보고 OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])

추상 기본 클래스

사실, 우리는 더 잘할 수 있습니다. collections다양한 유형에 최소 프로토콜을 적용하는 추상 기본 클래스를 제공합니다. 이 경우 Mapping프로토콜 만 기대 하면 다음을 수행 할 수 있으며 코드가 훨씬 유연 해집니다.

from collections import Mapping

def foo(a_dict):
    if not isinstance(a_dict, Mapping):
        raise ValueError('argument must be a dict')
    return a_dict

의견 답변 :

유형을 사용하여 여러 클래스를 확인하는 데 사용할 수 있습니다. type(obj) in (A, B, C)

예, 유형이 동일한 지 테스트 할 수 있지만 위 유형 대신 제어 유형에 여러 기준을 사용하십시오 (단, 해당 유형 만 허용하지 않는 한).

isinstance(obj, (A, B, C))

차이점 isinstance은 Liskov 대체로 알려진 속성 인 프로그램을 중단하지 않고 부모를 대신 할 수있는 서브 클래스 를 지원한다는 것입니다.

그러나 종속성을 반전시키고 특정 유형을 전혀 확인하지 않는 것이 좋습니다.

결론

따라서 우리는 대체 서브 클래스를 지원하기를 원하기 때문에 인스턴스의 정확한 클래스를 알 필요가 없다면 type타입 검사를 피하고 타입 검사를 선호 isinstance합니다.


your_module.py를 확인 isinstance(instance, y)하고 사용하는 곳에 from v.w.x import y해당 검사를 가져 오지만 인스턴스 instance를 생성 할 때 from x import yyour_module.py에서 y를 가져 오는 방법 대신 사용 하면 isinstance 검사는 동일한 클래스 임에도 불구하고 실패합니다.
toonarmycaptain

64

후자는 서브 클래스를 올바르게 처리하기 때문에 선호됩니다. 사실, isinstance()두 번째 매개 변수는 튜플 일 수 있으므로 예제를 훨씬 쉽게 작성할 수 있습니다.

if isinstance(b, (str, unicode)):
    do_something_else()

또는 basestring추상 클래스를 사용하십시오 .

if isinstance(b, basestring):
    do_something_else()


9

실제 사용 차이는 다음과 같이 처리하는 방법입니다 booleans.

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

isinstance(True, int)

isinstance(False, int)

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

type(True) == int

을 반환합니다 False.


0

실제 차이점에 대해서는에서 찾을 수 code있지만의 기본 동작 구현을 찾을 수 없습니다 isinstance().

그러나 __instancecheck__ 에 따라 비슷한 abc .__ instancecheck__을 얻을 수 있습니다 .

abc.__instancecheck__, 아래 테스트를 사용 후 :

# file tree
# /test/__init__.py
# /test/aaa/__init__.py
# /test/aaa/aa.py
class b():
pass

# /test/aaa/a.py
import sys
sys.path.append('/test')

from aaa.aa import b
from aa import b as c

d = b()

print(b, c, d.__class__)
for i in [b, c, object]:
    print(i, '__subclasses__',  i.__subclasses__())
    print(i, '__mro__', i.__mro__)
    print(i, '__subclasshook__', i.__subclasshook__(d.__class__))
    print(i, '__subclasshook__', i.__subclasshook__(type(d)))
print(isinstance(d, b))
print(isinstance(d, c))

<class 'aaa.aa.b'> <class 'aa.b'> <class 'aaa.aa.b'>
<class 'aaa.aa.b'> __subclasses__ []
<class 'aaa.aa.b'> __mro__ (<class 'aaa.aa.b'>, <class 'object'>)
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasses__ []
<class 'aa.b'> __mro__ (<class 'aa.b'>, <class 'object'>)
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'object'> __subclasses__ [..., <class 'aaa.aa.b'>, <class 'aa.b'>]
<class 'object'> __mro__ (<class 'object'>,)
<class 'object'> __subclasshook__ NotImplemented
<class 'object'> __subclasshook__ NotImplemented
True
False

나는이 결론을 얻는다 type.

# according to `abc.__instancecheck__`, they are maybe different! I have not found negative one 
type(INSTANCE) ~= INSTANCE.__class__
type(CLASS) ~= CLASS.__class__

의 경우 isinstance:

# guess from `abc.__instancecheck__`
return any(c in cls.__mro__ or c in cls.__subclasses__ or cls.__subclasshook__(c) for c in {INSTANCE.__class__, type(INSTANCE)})

BTW :보다 효율적으로 사용하는 혼합하지 않기 위하여 relative and absolutely import, 사용 absolutely importproject_dir에서을 (추가 sys.path)

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