Python

함수 이름으로 함수 호출하기

둔진 2020. 5. 5. 08:13

  함수 이름을 알고 있을 때, 그 이름으로 함수를 호출하고 싶을 때가 있습니다. 예를 들어, 함수의 이름이 tokenize 일 때 이 함수를 어떻게 호출할 수 있을까요?

  당연히 아래와 같이 호출합니다.

tokenize()

  너무나 당연하죠. 그런데 가끔 다르게 호출하고 싶을 수도 있습니다. 이렇게요.

f = getattr(sys.modules[__name__], 'tokenize')
f()

  굳이 왜죠. 왜 이렇게 어렵게. 프로그램 실행 중 동적으로 함수 이름을 알아내고, 이 함수를 호출해야 할 때가 있습니다.

예를 들어 한국어 토큰의 단위는 뭐가 좋을까? 에서 tokenize_by_morpheme_jaso, tokenize_by_morpheme_char, tokenize_by_eojeol_jaso, tokenize_by_eojoel_char 와 같이 함수들을 만들어두고, 명령형의 인자에 따라서 실제 tokenizer를 선택해서 썼습니다.

def get_tokenizer(method, unit):
    return getattr(sys.modules[__name__], 'tokenize_by_{}_{}'.format(method, unit))

  이렇게 하면 이름이 tokenize_by_[method]_[unit]인 함수를 찾아서 돌려줍니다. get_tokenizer('morpheme', 'jaso')를 호출하면, get_tokenizer_morpheme_jaso 함수를 반환해줍니다.

  getattr(object, name) 함수는 object 안의 이름이 name인 attribute를 돌려줍니다. 위의 경우는 sys.modules[__name__] object에서 'tokenize_by_morpheme_jaso' attirubte를 반환할 거고요.

  sys.modules는 현재 import된 모든 modules를 저장하고 있는 dict입니다. key는 module의 이름이고요.

  다음으로 __name__은 현재 실행되고 있는 module의 이름입니다. 즉, 간단히 말하면 현재 파일 정도 됩니다. (엄밀히 따지면 아니지만 간단한 이해를 돕기 위해서 현재로서는 이렇게...)

  위의 문장들을 하나로 합쳐보면, "현재 파일(Module)에 정의된 함수 중 이름이 tokenize_by_morpheme_jaso인 함수를 달라"입니다.

난 함수를 달라 -_-

  

  잘 쓰면 유용하지만 아주 조심해야할 점이 있습니다. 바로 code refactoring에 매우 취약하다는 점입니다. 예를 들어, tokenize_by_morpheme_jaso 함수를 나중에 tokenize_by_morpheme_unit_jaso로 변경했다고 가정해보겠습니다. 저 코드는 IDE나 Python 인터프리터가 잡지 못하고, 런타임에 죽기 때문에 아주 고약한 버그입니다.

  모든 도구가 그렇듯이 적절한 곳에 적절하게 잘 쓰는 것이 중요하겠죠. 이 기능도 마찬가지고요.