# 메서드 이름으로 파이선 메서드 호출하기

자바, C++ 등 여러 언어에서는 실행 중 객체가 어떤 값을 가지고 있고 어떤 메서드를 호출 할 수 있는지 코딩을 통해 알 수 있도록 리플랙션(Reflection) 기능을 지원합니다.

그렇다면 파이선은 어떤 방식으로 리플랙션을 지원할까요? 이번 글에서는 dir, getattr, callable 그리고 methodToCall을 사용해서 동적으로 객체의 메서드를 얻어내고, 원하는 메서드를 실행하는 방법을 알아보겠습니다.

# 1. 이슈

파이선으로 하이브 메타스토어를 이용한 코딩을 하던 중 문서와 예제가 부족하여 뭘 할 수 있고, 뭘 할 수 없는지 확인하고 싶었습니다. 하이브 소스코드나 메타스토어를 접근하는 소스코드를 보는 것이 정석이겠지만 우선 사용 가능한 메서드들을 모두 확인하는 것으로 시작하는 것이 시간을 절약할 수 있다는 생각에 객체로부터 메소드 목록을 얻는 방법을 찾았습니다.

이번 글의 제목은 메서드 이름으로 파이선 메서드 호출하기 이지만 하이브 메타스토어를 사용하기 위한 내용으로 시작합니다.

# 2. 하이브 메타스토어 클라이언트 얻기

스리프트 프로토콜을 이용한 하이브 클라이언트 인스턴스를 생성하는 코드입니다.

# 3. 예외처리!

위의 코드는 문제가 없지만 위에서 얻은 클라이언트를 바로 실행하면 아래와 같은 에러가 발생합니다.

client = get_client(_host_, _port_)
client.get_all_databases()

TTransportException: Transport not open

정상 동작하기 위해서 Transport open/close 처리를 해줍니다.

하이브가 관리하고있는 데이터베이스 목록이 출력됩니다.

# 4. 메서드 이름으로 메서드 호출하기

드디어 본론입니다. 매번 이렇게 앞뒤로 코드를 붙이기 귀찮으니 원하는 코딩 양을 줄이기 위해서 아래와 같이 감싸주는 코드를 작성했습니다. 클래스로 감싸서 생성자/소멸자에 open/close 코드를 넣는 방법도 있겠으나 1) 호출 깊이가 깊어지고 2) 코드양을 줄이고 싶은 마음과 3) 단순히 파이선의 리플랙션 방법을 본 갑자기 기억나서 아래와 같이 getattr을 찾아서 적용했습니다.

getattr은 객체로부터 메서드 이름을 통해 메서드의 위치를 얻어옵니다. 메서드가 어떤 매개변수가 필요할지 callit 함수 정의 시점에는 알지 못하기 때문에 *args로 가변길이 매개변수를 받을 수 있게 해줍니다. 이제 실행하는 코드입니다.

우선 객체가 가지고 있는 전체 메서드 목록을 얻어보고

[method for method in dir(client) if callable(getattr(client, method))]

['__init__',
 'add_index',
 'add_partition',
 ...
 'get_all_databases',
 'get_all_tables',
 'get_config_value',
 'get_database',
 'get_databases',
 'get_delegation_token',
 'get_fields',
 'get_index_by_name',
 'get_index_names',
 'get_indexes',
 'get_partition',
 'get_partition_by_name',
 'get_partition_names',
 ...
 'set_ugi',
 'shutdown']

get_all_databases 메서드를 호출해서 전체 데이터베이스 목록을 얻어옵니다.

callit('get_all_databases')

# 파이선 문맥 관리자 사용하기

위의 메서드 호출 방법이 동작하지만 파이선다운(Pythonic) 코드는 아닙니다. 다른 글에서 문맥 관리자(context manager) 기법에 대해서 더 알아보도록 하겠습니다.

# Appendix. 참고

파이선을 이용한 하이브 메타스토어 기본 사용법은 에어플로우 (airflow)의 코드를 통해 배웠습니다.

Last Updated: 3/23/2020, 11:10:33 PM