2.33. 인트로스펙션¶
몇 가지 내장 함수를 사용하면 실행 중인 프로그램이 자기 자신 – 다루고 있는 값들, 그 값들이 속한 네임스페이스, 클래스 간의 관계 – 을 들여다볼 수 있습니다. 객체가 호출자가 주장하는 것이 아니라 실제로 무엇인지 에 근거해 결정을 내려야 할 때 이들을 사용하세요.
2.33.1. 동일성과 해싱¶
id()– 객체가 살아 있는 동안 그 객체를 식별하는 고유한 정수입니다. 같은 객체를 바인딩한 두 이름은 같은 id를 반환하고, 같지만 별개인 두 객체는 그렇지 않습니다.
>>> a = [1, 2, 3]
>>> b = a
>>> c = [1, 2, 3]
>>> id(a) == id(b) # same list
True
>>> id(a) == id(c) # equal but distinct
False
id는 실행 간에 이식되지 않으며, “같은 객체냐 다른 객체냐”를 넘어서는 의미는 없습니다.
hash()– 객체의 해시 값으로,dict와set이 해당 객체를 조회할 때 사용하는 바로 그 숫자입니다. 같은 두 객체는 같은 값으로 해시되며, 해시 가능한 타입(대부분 불변 값)만이 동작합니다.
>>> hash("abc") # some integer, build-dependent
-1600925533
>>> hash([1, 2])
TypeError: unhashable type: 'list'
2.33.2. 타입과 호출 가능성 조회하기¶
type()– 값의 정확한 클래스입니다.type(x) is int는 “x가 정확히 int인가”(하위 클래스는 제외)를 묻습니다; 보통 원하는 것은isinstance()쪽입니다.isinstance()– “x가 이 클래스의 인스턴스이거나 그 하위 클래스의 인스턴스인가?” 함수 내부에서 타입 기반 분기를 할 때 쓰는 표준 도구입니다.issubclass()– 클래스 수준의 대응 함수입니다. 인스턴스가 아니라 두 개의 클래스를 받습니다.callable()– 인자를()로 호출할 수 있으면True입니다. 함수일 수도 있고 단순한 값일 수도 있는 인자를 받았을 때 유용합니다.
>>> isinstance(3, int)
True
>>> isinstance(True, int) # bool is a subclass of int
True
>>> issubclass(bool, int)
True
>>> callable(len)
True
>>> callable(10)
False
callable을 사용하는 패턴:
def call_or_return(x):
return x() if callable(x) else x
2.33.3. 범위 들여다보기¶
globals()– 모듈의 전역 네임스페이스를dict로 반환합니다. 여기서 읽는 것은 잘 동작하고, 쓰는 것도 실제로 반영되지만, REPL 탐색 외의 상황에서 그렇게 하면 프로그램을 따라가기 어려워집니다.locals()– 호출 지점의 지역 네임스페이스입니다. 함수 내부에서는 지역 변수를 반영하지만, 반환된 딕셔너리를 수정 하는 것이 실제 지역 변수에 다시 기록된다고 보장되지는 않습니다(구현에 따라 정의되는 동작).
name = "OpenMV"
def f():
x = 10
print(globals()["name"]) # OpenMV
print(locals()) # {'x': 10}
이 둘은 디버깅과, 무엇이 정의되어 있는지 발견해야 하는 도구에 유용합니다. 일반 코드에서는 아껴서 사용하세요 – globals() 를 변형하는 함수는 Python에서 가장 추론하기 어려운 것 중 하나입니다.
2.33.4. 참고¶
디버깅 에서 다루는 dir() 과 help() 는 알 수 없는 객체의 표면을 탐색하는 일상적인 인트로스펙션 도구입니다.