파이썬의 유형 점검 연구

창조적 공공재 라이센스
Average
4.0
Rated
1
Times
5
4
3
2
1
0
Submited by David
Last updated by David on 2008-05-09 16:48 (ver. 1)
Author(s): David

파이썬에서 유형-점검을 할 것이라고는 생각하지 않지만, 혹시라도 하게 된다면 어떤 방법이 가장 좋은지 알아야 한다. 내장 함수인 'type'과 'isinstance' 그리고 '__class__' 특성의 장점과 단점을 연구해 보겠다.

라이센스: 창조적 공공재 비-상업용 공유 Keywords: type checking classes

객체의 유형을 알 필요가 있는가? 짧게 말해 보겠다: 아니, 그럴 필요가 없다. 그냥 그 객체를 마치 예상대로의 유형인 것처럼 사용하고, 그 결과로 나온 에러를 처리하자.

한편으로 유형-점검은 편리하다. 구현하기도 쉬우며 디버깅할 때 참 편하다. 그러나 유형-점검으로는 가끔 문제를 공격하기 위한 확실한 방법이 없는 경우가 있다. (그렇지만 제일 먼저 생각해 보자.)

유형-점검을 하려면 몇 가지 방법이 있다: 내장 함수 typeisinstance 그리고 실체 특성인 __class__가 그것이다. 객체를 클래스와 비교하려면, 그 클래스에 직접 비교하든가, 아니면 (안전하게 전역 영역에) 'types' 모듈을 반입하여 (함수 같이) 사용자-접근 클래스를 제공하지 않는 유형에 접근해 볼 수 있다.

시작하기 전에, 파이썬에는 두 가지 유형의 클래스가 있음을 주목하자: '새-스타일'의 클래스는 object 클래스로부터 상속받으며, 그리고 '예전-스타일'의 클래스는 그렇지 않다. 거의 대부분의 고유 파이썬 유형은 이제 새-스타일의 클래스이지만, 여러분이 만든 클래스는 아마도 그렇지 않을 것이다.

몇 가지 실험을 해 보면서, 클래스의 이름을 인쇄해 본 다음, 그 유형을 클래스와 비교하자. 다음과 같은 클래스와 실체가 정의되어 있다고 생각하자:

 1from types import *
2
3# 새-스타일의 클래스의 실체
4class NewClass(object): pass
5
6new_class_instance = NewClass()
7
8def function(): pass
9
10string = 'This is a string!'
11
12# 예전-스타일 클래스의 실체
13class OldClass: pass
14
15old_class_instance = OldClass()

type__class__를 사용하여 클래스의 이름을 인쇄해 보자. isinstance로는 그렇게 할 방법이 없다:

 1print type(new_class_instance)
2print new_class_instance.__class__
3# 둘 다 "<class '__main__.new_class'>"를 인쇄한다
4
5print type(function)
6print function.__class__
7# 둘 다 "<type 'function'>"를 인쇄한다
8
9print type(string)
10print string.__class__
11# 둘 다 "<type 'str'>"를 인쇄한다
12
13print type(old_class)
14# "<type 'instance'>"를 인쇄한다
15
16print old_class.__class__
17# 다음과 같이 인쇄된다: "class __main__.OldClass at 0x00F7F"
18# type()에 의하여 인쇄된 것과 다름에 주목하자

마치 type이 예전-스타일의 클래스에 작동하지 않는 것처럼 보인다. 이제 클래스나 유형을 점검해 보자. typeisinstance 그리고 __class__를 사용한다:

 1type(new_class_instance) == NewClass
2isinstance(new_class_instance, NewClass)
3new_class_instance.__class__ == NewClass
4# 모두 다 참을 돌려준다
5
6type(function) == FunctionType # 'types' 모듈로부터
7isinstance(function, FunctionType)
8function.__class__ == FunctionType
9# 모두 다 참을 돌려준다
10
11type(string) == str # 'types' 모듈에서 StringType을 사용할 수도 있다
12isinstance(string, str)
13string.__class__ == str
14# 모두 참을 돌려준다
15
16type(old_class_instance) == OldClass
17# 거짓을 돌려준다. old_class_instance가 OldClass의 실체인데도 말이다.
18# 'type'은 이것들을 이해하지 못한다.
19
20isinstance(old_class_instance, OldClass)
21old_class_instance.__class__ == OldClass
22# 둘 다 예상대로 참을 돌려준다

확실히, type은 유형 인쇄와 유형 비교에 모두 완전히 쓸모가 없다. 예전-스타일의 클래스를 이해하지 못하기 때문이다. 반면에 __class__는 이해한다.

__class__는 난잡하지만, 클래스의 유형에도 작동하고 원한다면 클래스의 이름도 인쇄해 주는 유일한 방법이다. 보고 있는 객체가 어떤 유형인지 알지 못할 때 디버깅에 최고의 선택이다.

isinstance도 모든 객체에 작동한다. 또다른 장점도 있다: 실제로 건넨 객체가 클래스의 실체인지 또는 클래스의 하위클래스인지 점검한다. 일반적으로 유형-점검을 하려는 이유는 메쏘드의 존재나 그 행위에 관심이 있기 때문이다. 목표 클래스의 모든 하위클래스는 아마도 그 메쏘드를 가지고 있을 가능성이 높다. 그래서, isinstance더 정확하다. 게다가, 클래스를 터플에 담아 건네면 그 안의 모든 클래스를 점검해 준다. 이런 장점들 덕분에 실제 프로그램에서 합법적인 유형-점검에 최고의 선택이 된다.

다음은 지금까지 연구한 결론이다:

메쏘드 예전-스타일의 클래스에 작동하는가? 호출 전에 유형을 알 필요가 있는가? 잘맞는 분야
type No No 실제로는 쓸모 없다
isinstance Yes Yes 합법적인 유형-점검: 클래스 유형을 점검하고자 할 때
__class__ Yes No 디버깅: 실체가 어떤 클래스에 속하는지 모를 때