사용자 도구

사이트 도구


research:pythoncallbyname

파이썬의 함수 및 변수를 이름으로 호출하기

문제 정의

어떤 프로젝트에서 여러 함수를 호출하는 루틴을 필요로 한다. 그런데 이 함수의 이름 및 인자 목록은 상황에 따라 변할 수 있고, 함수의 호출 타이밍도 조금씩 변화시킬 필요가 있다고 한다.

그래서 프로젝트원은 함수 호출 및 함수에 필요한 인자를 미리 '스크립트화'하여 프로그램 안에서 보다 유연하게 함수 및 인자 호출을 할 수 있도록 프로그램을 디자인하고 싶어 한다. 이럴 때는 과연 어떻게 해야 할까?

해결 방법

파이썬에는 모든 함수 및 변수 (이것들은 파이썬에서 모두 '객체(object)'로 취급된다) 목록들이 내부적인 '테이블'에 기록되어 있다. 이 '테이블'이란 오브젝트의 인스턴스 이름을 키로 하고 오브젝트 자체가 내용인 딕셔너리 형태로 구성되어 있다. 그러므로 프로그램 내부에서 쓰이는 오브젝트의 이름만 정확히 지칭할 수 있으면 얼마든지 그 이름을 이용해 실제 객체에 접근할 수 있다.

관련 라이브러리 및 함수

locals()

빌트인 함수로써 현재 스코프 내에서의 오브젝트들 테이블을 호출한다.

레퍼런스

globals()

빌트인 함수로써 현재 글로벌 스코프 내에서의 오브젝트 테이블을 호출한다.

레퍼런스

getattr(), hasattr()

getattr, hasattr 역시 빌트인 함수이다. 시그니쳐는 다음과 같다.

getattr(object, name[, default])
hasattr(object, name)

getattr은 해당 오브젝트 object 안에 어트리뷰트 이름인 name이 존재한다면 그 객체를 리턴한다. 만일 발견되지 않는다면 default를 리턴한다. hasattr은 오브젝트 내부에 어트리뷰트가 존재하는지 파악하여 불리언 값을 리턴한다.

레퍼런스 레퍼런스

구현 및 설명

간단한 코드를 통해 예를 들어 보자

obj_by_name.py
#coding: utf-8
def criteria_1(param_1):
	print 'criteria 1'
	print 'param_1:', param_1
	print ''
 
def criteria_2(param_1, param_2):
	print 'criteria 2'
	print 'param_1:', param_1
	print 'param_2:', param_2
	print ''
 
def criteria_3(param_1, param_2, param_3):
	print 'criteria 3'
	print 'param_1:', param_1
	print 'param_2:', param_2
	print 'param_3:', param_3
	print ''
 
def call_wrapper(func_name, var_list):
	varcls = variables()
	func   = globals()[func_name]
	params = {}
 
	for var in var_list:
		params[var] = getattr(varcls, var)
 
	func(**params)
 
class variables:
	def __init__(self):
		self.param_1 = 'variable1'
		self.param_2 = 12.25
		self.param_3 = (1, 2, 3)
 
# test
# function names and variable names
function_names = ['criteria_1', 'criteria_2', 'criteria_3']
var_names      = ['param_1', 'param_2', 'param_3']
 
# run criteria_1 only by names
call_wrapper('criteria_1', ['param_1'])
call_wrapper('criteria_2', ['param_1', 'param_2'])
call_wrapper('criteria_3', ['param_1', 'param_2', 'param_3'])

호출해야 할 함수의 종류는 3가지이며, 이 함수의 이름과 인자는 각각 조금씩 다르다. 스크립트가 실행되는 '# test' 주석 이후의 코드에서 함수를 호출하기 위한 이름과 인자를 미리 문자열로 지정해 두었다. 이 이름은 호출되는 함수의 인자명과 동일해야 한다.

각 인자 이름과 매칭되는 실제 값들은 'variables'라는 클래스에서 지정을 한다. 여기서 약간의 제약이 존재한다. 스크립트를 통해 일괄적으로 클래스 내부의 어트리뷰트의 실제 객체로 접근하려면 클래스 내부의 변수 이름 또한 함수의 인자명과 동일하게 해 주는 것이 용이하다. 물론 다르게 해 줄 수도 있지만, 그렇게 하려면 추가적인 연산이 필요하므로 가능한한 맞추어 주는 것이 좋다.

call_wrapper 함수는 스크립느를 통해 실행될 함수의 이름과 각 함수의 인자를 '문자열'의 형태로 전달한다. 그러면 call_wrapper 함수는 실제 함수 객체와 함수에 필요한 인자의 목록을 딕셔너리 형태로 저장한다.

그리고 func(**params)라는 구문에서 목표로 하는 함수에 정확히 원하는 인자를 제공하게 된다. 딕셔너리 구조체를 위처럼 입력하는 구문은 매우 톡특한 파이썬 문법이다. (다른 언어도 이러한 형식을 지원하는지?)

그러므로 초기 function_names, var_name에 대한 룰을 구체적으로 정의하면 미리 함수 호출 및 인자값을 스크립트화하여 원하는 타이밍에 맞춰 함수호출을 자유자재로 유연히 호출할 수 있을 것이다. call_wrapper 내부에서 필요한 객체에 접근하기 위해 부가적으로 locals, getattr 등의 함수 호출이 발생하나, 딕셔너리 객체에 의한 검색이므로 프로그램의 유연성에 비해 지불하는 오버헤드는 매우 미미하다고 볼 수 있다.

research/pythoncallbyname.txt · 마지막으로 수정됨: 2014/10/09 21:24 저자 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki