질문자 :abbot
이 두 코드 조각의 차이점은 무엇입니까?
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
동일성을 확인하는 것은 그렇지 않습니다(유형 및 하위 유형(일명 하위 클래스)의 인스턴스를 거부합니다.
일반적으로 Python에서는 코드가 상속을 지원하기를 원합니다(상속이 매우 편리하기 때문에 코드를 사용하는 코드를 사용하지 못하도록 막는 것은 좋지 않습니다!). 따라서 isinstance
type
s의 ID를 확인하는 것보다 덜 나쁩니다. 상속을 원활하게 지원합니다.
isinstance
가 좋은 것은 아닙니다. 유형의 동일성을 확인하는 것보다 덜 나쁘다 는 점을 염두에 두십시오. 일반적이고 Pythonic에서 선호하는 솔루션은 거의 항상 "오리 타이핑"입니다. 인수 를 원하는 특정 유형인 것처럼 사용하고, 인수가 사실이 아닌 경우 발생할 수 있는 모든 예외를 catch try
/ except
그 유형의 (또는 그것을 멋지게 오리 흉내내는 다른 유형;-), 그리고 except
절에서 다른 것을 시도하십시오(인수 "마치 다른 유형인 것처럼" 사용).
basestring
은 isinstance
str
및 unicode
하위 클래스 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 가 받아들여지고 Python 2.6 및 3.0부터 구현되었기 때문에 Python에서 분명히 성장하는 개념입니다.
PEP는 ABC가 종종 오리 타이핑을 대체할 수 있지만 일반적으로 그렇게 해야 하는 큰 압력이 없음을 분명히 합니다( 여기 참조). 그러나 최근 Python 버전에서 구현된 ABC는 추가 isinstance
(및 issubclass
)는 이제 "[an instance of] 파생 클래스" 이상을 의미할 수 있습니다(특히 모든 클래스는 ABC에 "등록"될 수 있으므로 하위 클래스로 표시되고 해당 인스턴스는 ABC의 인스턴스로 표시됩니다. ABC는 또한 Template Method 디자인 패턴 응용 프로그램을 통해 매우 자연스러운 방식으로 실제 하위 클래스에 추가적인 편의를 제공할 수 있습니다(ABC와 무관한 일반적으로 특히 Python에서 TM DP에 대한 자세한 내용은 여기 및 여기 [[part II]] 참조). .
Python 2.6에서 제공되는 ABC 지원의 기본 메커니즘은 여기를 참조하십시오. 매우 유사한 3.1 버전의 경우 여기를 참조하십시오. 두 버전 모두에서 표준 라이브러리 모듈 컬렉션 (3.1 버전—매우 유사한 2.6 버전의 경우 여기 참조)은 몇 가지 유용한 ABC를 제공합니다.
이 답변의 목적을 위해 ABC(UserDict.DictMixin 과 같은 믹스인 클래스의 고전적인 Python 대안과 비교하여 TM DP 기능에 대한 틀림없이 더 자연스러운 배치 이상)에 대해 유지해야 할 핵심 사항 isinstance
(및 issubclass
)를 만드는 것입니다. 이전(2.5 및 이전 버전)보다 훨씬 더 매력적이고 널리 퍼져 있습니다(Python 2.6 및 앞으로). 따라서 대조적으로 최근 Python 버전에서는 유형 동등성 검사를 이미 사용하던 것보다 훨씬 더 나쁜 관행으로 만듭니다.
Alex Martelliisinstance
type
할 수 없는 것을 달성하는 예입니다.
class Vehicle: pass class Truck(Vehicle): pass
이 경우 트럭 개체는 차량이지만 다음을 얻게 됩니다.
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에서 객체 유형을 비교하는 방법?
Peterisinstance()
와 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의 하위 클래스인 dict
를 전달하려고 하면(우리 코드가 Liskov Substitution 의 원칙을 따를 것으로 기대한다면 하위 유형이 유형을 대체할 수 있음) 코드가 중단됩니다!:
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(obj) in (A, B, C)
사용하여 여러 클래스를 검사하는 데 사용할 수 있습니다.
예, 유형의 동일성을 테스트할 수 있지만 위의 대신 해당 유형만 허용하지 않는 한 제어 흐름에 대해 다중 기반을 사용합니다.
isinstance(obj, (A, B, C))
차이점은 isinstance
가 Liskov 치환으로 알려진 속성인 프로그램을 달리 중단하지 않고 부모를 대체할 수 있는 하위 클래스를 지원한다는 것입니다.
그러나 더 나은 방법은 종속성을 반전하고 특정 유형을 전혀 확인하지 않는 것입니다.
결론
따라서 우리는 서브클래스 대체를 지원하기를 원하기 때문에 대부분의 경우 유형을 사용한 type
검사를 피하고 인스턴스의 정확한 클래스를 알아야 하는 경우가 아니면 isinstance
사용한 유형 검사를 선호합니다.
Aaron Hall후자가 하위 클래스를 적절하게 처리하기 때문에 선호됩니다. isinstance()
의 두 번째 매개변수가 튜플일 수 있기 때문에 예제를 훨씬 더 쉽게 작성할 수 있습니다.
if isinstance(b, (str, unicode)): do_something_else()
또는 기본 basestring
추상 클래스를 사용하여:
if isinstance(b, basestring): do_something_else()
John Millikinbooleans
을 처리하는 방법입니다.
True
와 False
는 파이썬에서 1
과 0
을 의미하는 키워드일 뿐입니다. 따라서,
isinstance(True, int)
그리고
isinstance(False, int)
둘 다 True
반환합니다. 두 부울 모두 정수의 인스턴스입니다. type()
이 더 영리합니다.
type(True) == int
False
반환합니다.
Alecpython 문서에 따르면 다음과 같은 진술이 있습니다.
int()
및 str()
과 같은 내장 팩토리 함수도 해당 유형의 이름입니다.
따라서 isinstance()
type()
보다 선호되어야 합니다.
Xinus실제 차이점은 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
나는 다음과 같은 결론을 얻었습니다. For 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)})
relative and absolutely import
를 혼합하지 않는 것이 좋습니다. absolutely import
from project_dir( sys.path
추가)
Cheney출처 : http:www.stackoverflow.com/questions/1549801/what-are-the-differences-between-type-and-isinstance