python - typecheck - 파이썬 변수 타입




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

이 두 코드 조각의 차이점은 무엇입니까? 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()

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

유형 검사

isinstance(obj, Base)

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

isinstance(obj, (Base1, Base2))

타입 검사는

type(obj) is Base

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

sidenote로서,보다 가능성이 높습니다

type(obj) == Base

왜냐하면 클래스는 싱글 톤이기 때문입니다.

타입 검사를 피함 - 다형성 (오리 - 타이핑) 사용

파이썬에서는 일반적으로 인수에 대해 모든 유형을 허용하고 예상대로 처리하며 객체가 예상대로 작동하지 않으면 해당 오류가 발생합니다. 이것은 다형성 (duck-typing)이라고도 알려져 있습니다.

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

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

function_of_duck(mallard)

또는 그 오리처럼 작동 :

function_of_duck(object_that_quacks_and_swims_like_a_duck)

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

그러나 명시 적으로 유형을 확인하는 것이 바람직한 경우가 있습니다. 아마도 당신은 다른 객체 유형들과 합리적인 것들을 가지고있을 것입니다. 예를 들어 판다 데이터 프레임 개체는 사전 이나 레코드로 구성 될 수 있습니다. 이 경우, 당신의 코드는 그것이 적절하게 처리 할 수 ​​있도록 어떤 타입의 인자가 있는지를 알아야한다.

그래서 질문에 답하기 위해서 :

파이썬에서 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의 하위 클래스 인 dict 을 전달하려고하면 (우리가 할 수있는 한, Liskov Substitution 의 원칙을 따르는 코드를 기대한다면 그 subtype을 유형으로 대체 할 수 있습니다) 코드가 중단됩니다!

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

그러나 isinstance 를 사용하면 Liskov Substitution을 지원할 수 있습니다! :

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은 type(obj) in (A, B, C) 사용하여 여러 클래스를 검사하는 데 사용할 수 있습니다.

네, 타입의 평등을 테스트 할 수 있습니다. 그러나 위의 메소드 대신 컨트롤 플로우를위한 멀티베이스를 사용하십시오.

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

차이점은 isinstance 가 부모를 대신 할 수있는 하위 클래스를 지원한다는 점입니다. Liskov 대체로 알려진 속성입니다.

그러나 더 나은, 비록, 당신의 의존성을 반전하고 전혀 특정 유형을 확인하지 마십시오.

결론

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


다른 (이미 좋은!) 답변의 내용을 요약하기 위해 상속을위한 isinstance (파생 클래스 인스턴스도 기본 클래스 인스턴스입니다.) type 평등을 검사하는 것은 아닙니다. 하위 유형 인 AKA 서브 클래스의 인스턴스를 거부합니다.

일반적으로 파이썬에서는 상속을 지원하는 코드를 원한다. (상속이 아주 편리하기 때문에 코드를 사용하면 코드를 사용하지 못하게 될 것이다!) 따라서 isinstancetype s의 ID를 검사하는 것보다 나쁘지 않다. 상속을 완벽하게 지원합니다.

그것은 isinstance좋다고 생각하지 않습니다. 여러분을 생각해보십시오. 이것은 평등 유형을 검사하는 것 보다 나쁘지 않습니다 . 보통 Python의 선호 솔루션은 거의 항상 "duck typing"입니다 : 원하는 특정 유형의 것처럼 인수 사용하거나, 인수가 사실이 아닌 경우 발생할 수있는 모든 예외를 포착하는 try / except 문에서 수행하십시오 (또는 어떤 다른 유형이 멋지게 오리 흉내 내고 ;-), except 절에서 (다른 형식의 "as if"인수를 사용하여) 다른 것을 시도해보십시오.

그러나 basestring isinstance ( strunicode 서브 클래스의 basestring 모두)를 사용할 수 있도록하는 데만 사용되는 내장 유형 인 상당히 특별한 경우입니다. 문자열은 연속적입니다 (반복 할 수 있고, 색인을 생성하고, 조각을 만들 수 있습니다 ...). 그러나 일반적으로 문자열을 "스칼라"유형으로 취급하려고합니다. 모든 종류의 문자열을 처리하는 것은 다소 불편합니다 (그러나 합리적으로 자주 사용하는 경우). 문자열 (및 다른 스칼라 유형, 즉 루프 할 수없는 스칼라 유형)은 한 가지 방법, 모든 컨테이너 (목록, 세트, ​​dicts ...)를 다른 방법으로 사용하고 basestring plus isinstance 는 전체 구조 이 관용구의 내용은 다음과 같습니다.

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

basestring추상 기본 클래스 ( "ABC")라고 말할 수 있습니다. 하위 클래스에 대한 구체적인 기능은 제공하지 않지만 주로 isinstance 와 함께 사용하기위한 "마커"로 존재합니다. 이 개념은 Python에서 점점 커지는 개념입니다. PEP 3119 는 일반화를 소개하고 Python 2.6 및 3.0부터 시작하여 구현되었습니다.

PEP는 ABC가 종종 오리 타이핑을 대체 할 수 있지만, 일반적으로이를 수행 할 큰 압력이 없다는 것을 분명히합니다 ( here 참조). 최근의 Python 버전에서 구현 된 ABC는 특별한 isinstance 제공합니다. isinstance (및 issubclass )는 이제 "파생 된 클래스의 인스턴스"이상의 것을 의미 할 수 있습니다 (특히 어떤 클래스도 ABC에 "등록"될 수 있습니다. ABC의 인스턴스로 서브 클래스 및 인스턴스로 표시됩니다. 또한 ABC는 Template Method 디자인 패턴 응용 프로그램을 통해 실제 서브 클래스에 추가 편의를 제공 할 수 있습니다 (일반적으로 특히 ABC와는 별도로 TM DP에 대한 자세한 내용은 herehere [2 부 참조]). .

Python 2.6에서 제공되는 ABC 지원의 기본 메커니즘은 here 참조 here . 3.1 버전의 경우 매우 비슷 here . here 참조 here . 두 버전 모두 표준 라이브러리 모듈 collections (3.1 버전)은 유용한 ABC를 제공합니다.

이 대답의 목적을 위해, ABC에 대해 유지해야 할 중요한 것 ( UserDict.DictMixin 과 같은 mixin 클래스의 고전적인 Python 대안에 비해 TM DP 기능에 대한 논란의 여지는 있지만 자연스럽게 배치하는 것보다)는 isinstance (및 issubclass ) 파이썬 2.6과 이후 버전에서는 2.5와 그 이전 버전보다 훨씬 매력적이고 보급 적이기 때문에, 최근의 파이썬 버전에서는 유형 평등을 검사하는 것을 기존 방식보다 훨씬 더 실천하게 만듭니다.


여기 isinstancetype 것보다 낫다.

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 는 하위 클래스에도 적용됩니다.

또한보십시오 : Python에서 객체의 타입을 비교하는 방법?


파이썬 문서에 따르면 다음 문장이 있습니다.

8.15. types - 내장 유형의 이름

파이썬 2.2부터는 int()str() 과 같은 빌트인 팩토리 함수도 해당 유형의 이름이다.

따라서 isinstance()type() 보다 우선되어야합니다.





types