블로그 이미지
kalstein

여러가지 프로그래밍 관련이나...신변잡기적인 글들을 남기는 블로그입니다. 지식은 나누는만큼 강력해집니다 ^^

Rss feed Tistory
Programming/Python 2008. 12. 30. 12:31

Python에서 동적(?) 함수 호출

요즘 python을 개인적으로 관심있게 보고있는데...한가지 의문이 생겼더랜다.

'스크립트 언어지만, 실제 .py 코드가 동작하는것은 이미 쓰여진 코드. 그러면 runtime에 코드를 동적으로 생성해서 실행하는것이 가능할까?'

자세히는 보지않아서 정확한 구현을 어떻게 하는지는 기억이 나지는 않지만, C/C++쪽에서도 실시간으로 op code를 만들 수 있다. 비단 C/C++뿐만 아니라 .NET 환경하에서도 가능하다. (예전 windows들도 상당히 즐겨썼다고 한다. asm을 만들어서 끼워넣는 방법. Beautiful code 라는 책에서 살펴볼 수 있다)
그렇다면 python은??

일단 함수,클래스 들의 호출은 kldp에 문의해서 알아봤다 ㅎㅎ (링크)

__dict__ 를 사용하면 될꺼같은데요.
만약 인터프레터에서 나가고 싶으면 exit() 을 처도 되지만,
__buitlins__.__dict__["exit"]() 을 처도 나가집니다. ㅎㅎ.
다른 예로...

>>> class Foo:
... def bar(self):
... print "Hello, world"
...
>>> a = Foo()
>>> a.bar()
Hello, world
>>> Foo.__dict__
{'__module__': '__main__', 'bar': , '__doc__': None}
>>> Foo.bar(a)
Hello, world
>>> Foo.__dict__['bar'](a)
Hello, world
>>>

이 코드에선 a.bar(), Foo.bar(a), 와 Foo.__dict__['bar'](a) 가 다 같은 뜻을 가집니다 ㅎㅎ. 만약 문자열을 가지고 함수를 부르고 싶으면 __dict__['문자열'] 을 해버리면 되겟군요.

오호라...역시 되는구나.
그렇다면 조금 다른 활용을 살펴보도록 하자. 보통 OOP에서의 동적 함수 호출이라고 하면 C++로 표현해서 다음과 같은걸 의미한다.

class Base
{    virtual void foo() = 0; };

class Derived_1
{    virtual void foo() { 어쩌구; } };

class Derived_2
{    virtual void foo() { 저쩌구; } };

그리고는 실제 호출시에는 Base의 포인터만을 이용해서 호출하는 방식. 이방식의 문제점이라면...Factory Pattern을 쓴다고 했을때, type별로 매칭되는 뭔가를 따로 만들어줘야 한다는거지. id라고나 할까? id가 1이면 Derived_1을 생성해주고, 2이면 Derived_2를 생성해주고.

자 예제 코드 --->>
Base * FactoryMethod(int class_id)
{
    if (1 == id)
        return new Derived_1();
    else if (2 == id)
        return new Derived_2();
    else
        return NULL;
}

요런식으로 된다. 그런데...그냥 따로 id 받지않고 클래스 명을 받을수도 있지않을까? 또 코드로 말하자면 --->>
Base * FactoryMethod(const string class_name)
{    return new class_name(); }

이렇게 말이다. 좀 어이없을수도...;; C/C++에선 쉽지않을꺼다. (가능할까? 흠...잘 모르겠네...;;) 그런데 python은 저게 된다 -_-;;;; 컴파일을 인터프리터로 할 수 있기때문에 가능하다. 아래의 코드.

-------------------------------------------------------------
import codeop

class T1:
    def Eval(self, val):
        print val

class T2:
    def Eval(self, val):
        print 2 * val

tmpcodeobj = codeop.compile_command('obj = T1()')
eval(tmpcodeobj)
obj.Eval(10)
-------------------------------------------------------------

위의 코드에서 'obj=T2()' 이렇게 문자열을 바꾸면 T2:Eval() 이 호출된다. ^^;
스크립트 언어의 위대함이랄까...;;;
,
TOTAL TODAY