파이썬은 함수에서 다른 함수를 호출할 때 어떻게 선언 순서에 상관없이 호출할 수 있는 것이죠?

조회수 14911회

예를 들어, C의 경우


int Fun1(){}
int Fun2(){    //Fun2가 Fun1보다 위로 올라가면 에러
    Fun1();
}

혹은,

int Fun1(); //선언부
int Fun2(); 

BLAH BLAH

int Fun1(){} //구현부
int Fun2(){    
    Fun1();
}

식으로 하여야만 작동합니다.

근데 파이썬은


def Fun1():
    Fun2()    #순서 따윈 중요하지 않아.

def Fun2():
   test

등도 무리없이 작동하는 것 같습니다.

사실 좀 받아들이기 힘듭니다. 앞에서 어떤 함수가 있으며 이걸 어떤 형태로 쓸 것인지 알려주지 않았는데, 이렇게 근본없이 막 가져다 쓸 수 있다는게.

이게 어떻게 가능한 것인가요? Fun1의 선언시에는 Fun2가 무엇인지 모르는데.

타잎체크를 구동시에 하기 때문에 가능한 것일까요? 약타입이라서? 하지만 저때는 타입이 문제가 아니라 있는지 없는지조차 모릅니다.

아니면 다른 이유가 있을까요?

2 답변

  • 좋아요

    2

    싫어요
    채택 취소하기

    파이썬은 해당 심볼이 있는지 없는지를 런타임에서 합니다. 이 말은 코드 작성 단계에서 보이지 않는 심볼일 지라도 코드가 실행 중에 해당 심볼이 메모리에 올라와있다면 접근 가능하다 라고 생각하시면 됩니다.

    인터프리터는 코드를 한줄 한줄 실행해 나갈 때 심볼 이름을 발견하면 심볼 테이블에서 이름에 해당하는 객체를 가져와 코드를 수행하게 됩니다. 그러므로 변수나 함수를 정의하면 인터프리터는 심볼 테이블에 해당 심볼을 등록합니다.

    말씀하신 코드를 아래와 같이 수정하고 실행하였습니다. globals 은 전역에 존재하는 심볼의 테이블을 확인할 수 있습니다.

    print(globals())
    
    def Fun1():
        print(globals())
        Fun2()    #순서 따윈 중요하지 않아.
    
    print(globals())
    
    def Fun2():
        print("test")
    
    Fun1()
    

    결과는 아래와 같습니다.

    {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__file__': '/home/deploy/src/solution.py', '__doc__': None, '__package__': None}
    {'Fun1': <function Fun1 at 0x7fbced2515f0>, '__builtins__': <module '__builtin__' (built-in)>, '__file__': '/home/deploy/src/solution.py', '__package__': None, '__name__': '__main__', '__doc__': None}
    {'Fun1': <function Fun1 at 0x7fbced2515f0>, 'Fun2': <function Fun2 at 0x7fbced251668>, '__builtins__': <module '__builtin__' (built-in)>, '__file__': '/home/deploy/src/solution.py', '__package__': None, '__name__': '__main__', '__doc__': None}
    test
    

    결과를 보면 Fun1 이 호출 되기 전에는 Fun1Fun2 가 심볼 테이블에 존재하지 않습니다. 이후 def 를 통해 Fun1 이 정의되면, 심볼 테이블에서 Fun1 을 볼 수 있습니다. Fun2 의 경우도 마찬가지입니다.

    Func1 이 호출된 직후의 심볼 테이블을 보면 Fun2 가 존재하는 것을 확안할 수 있고, 당연히 존재하기 때문에 호출이 가능합니다.

    물론 Fun1 이 정의된 시점에서는 Fun2 가 없지만, 해당 함수가 호출되는 시점에 해당 심볼이 존재하면 문제없이 호출이 가능합니다.

    반대로 Fun2 를 심볼테이블에서 제거를 해보면 아래와 같습니다.

    print(globals())
    
    def Fun1():
        print(globals())
        Fun2()    #순서 따윈 중요하지 않아.
    
    print(globals())
    
    def Fun2():
        print("test")
    
    del globals()["Fun2"]
    Fun1()
    
    Traceback (most recent call last):
    File "/solution.py", line 15, in <module>
    Fun1()
    File "/solution.py", line 7, in Fun1
    Fun2() #순서 따윈 중요하지 않아.
    NameError: global name 'Fun2' is not defined
    

    위에서 말씀드렸듯이 심볼을 실행 시점에서 찾기 때문에 Fun1 을 호출하기 전에 해당 심볼을 삭제할 경우 Fun1Fun2 을 찾지 못하는 것을 볼 수 있습니다.

    정리

    파이썬은 심볼을 정의되는 시점이 아니라 실행되는 시점에서 찾기 때문에 앞에 정의되지 않는 심볼을 사용할 수 있습니다.

    이런 것은 타입과 관련된 특성이라기보단 스코프 에 관련된 내용입니다. 해당 링크를 확인하시면 조금더 도움이 되실 거에요.

    • 감사합니다. 단순한 파이썬 문법이 아닌 이런 작동원리를 다루는 책을 하나 추천해주실 수 있으신가요? 광자 2017.12.11 10:10
  • 윗 분이 정리를 매우 잘하셨네요!!..

    저는 질문하신 문제와 관련된, 또 다른 문제인 Delegation에 대한 주소를 남겨둘게요...

    약간 심화학습 비스므리한 느낌 ㅋㅋ;

    Language support for delegation

    In languages that support delegation via method lookup rules, method dispatching is defined the way it is defined for virtual methods in inheritance: It is always the most specific method that is chosen during method lookup. Hence it is the original receiver entity that is the start of method lookup even though it has passed on control to some other object (through a delegation link, not an object reference).

    Delegation has the advantage that it can take place at run time and affect only a subset of entities of some type and can even be removed at run time. Inheritance, by contrast, typically targets the type rather than the instances, and is restricted to compile time. On the other hand, inheritance can be statically type-checked, while delegation generally cannot without generics (although a restricted version of delegation can be statically typesafe[6]). Delegation can be termed "run-time inheritance for specific objects."

    Here is a pseudocode example in a C#/Java like language:

    https://en.wikipedia.org/wiki/Delegation_pattern

    https://en.wikipedia.org/wiki/Delegation_(object-oriented_programming)

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)