함수 이름을 알고 있을 때, 그 이름으로 함수를 호출하고 싶을 때가 있습니다. 예를 들어, 함수의 이름이 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 인터프리터가 잡지 못하고, 런타임에 죽기 때문에 아주 고약한 버그입니다.
모든 도구가 그렇듯이 적절한 곳에 적절하게 잘 쓰는 것이 중요하겠죠. 이 기능도 마찬가지고요.
'Python' 카테고리의 다른 글
bad magic number in 'application': b'\x03\xf3\r\n': ImportError (0) | 2020.05.19 |
---|---|
알쏭달쏭 Python import - sys.path (7) | 2020.05.15 |
함수의 인자를 특정 값으로 고정하기 - functools.partial (0) | 2020.05.12 |
Shell 명령의 결과를 받아오고 싶을 때 (0) | 2020.05.01 |
간편한 Progress Bar 모듈 - tqdm (0) | 2020.04.26 |