파이썬 변수의 범위 관련 질문

조회수 1045회
a=0
def vartest(a):
    a=1
    return a

print(vartest(a))

a=0을 지우면 a가 정의되지 않았다고 하나요? 함수 안의 a와 함수 밖의 a는 다른 변수이기 때문에 a=0의 유무와 상관없이 함수 내에서 a=1이라고 정의했으니, print(vartest(a))를 실행했을 때 a=1 print(a)을 실행한 것과 같은 결과가 나와야 하는 것 아닌가요?

  • 아래 설명에 부연하자면, 함수는 호출되기 전에는 실행되지 않습니다. vartest(a)로 호출하는 시점에는 함수 내부의 변수a의 할당문은 아직 실행되기 이전이라 변수a는 메모리상에 존재하지 않고, 존재하지 않으니 값1도 없습니다. 따라서 아직 생성되지 않은 변수a를 인자로 함수를 호출하게 되므로 에러가 발생할 수밖에 없습니다. 알 수 없는 사용자 2019.4.11 12:36
  • 아직 기초단계를 배우고 있어서 그런지 이해가 쉽진 않네요. 호출하는 시점이라는게 print(vartest(a))를 실행하는 시점으로 이해했어요. 근데 그 시점에 할당문이 아직 실행되기 이전이라는 말이 이해가 잘 안되네요.. 실행되는 순간 a라는 변수에 1을 저장(정의)한다고 생각했는데 이 생각이 잘못된건가요? a=0이 없다는 가정에서요! limephan 2019.4.11 16:35
  • 아 이제보니 print(vartest(a))에서 a는 함수 외부의 변수인데 정의를 하지 않아서 존재하지 않다고 하신거였군요.. 매개변수의 역할을 이해하지 못하고 vartest(a)을 그대로 적어 호출하면 코드블록대로 실행이 된다고 잘못 생각한것 같습니다. 답변 감사합니다. limephan 2019.4.11 19:57
  • 함수 선언문에 있는 파라미터 a는 함수 vartest의 지역변수. 함출호출할 때 사용된 변수 a는 함수와 무관한 전역변수...그리고 함수선언했다고 함수 내에서의 할당문 등이 실행되는 것은 아닙니다. 함수 내부의 명령들이 실행되는 시점은 그 함수를 호출할 때 비로소 실행됩니다. 그리고 그 함수가 종료되면, 함수의 변수들은 메모리에서 자동적으로 삭제됩니다. 다만, 나중에 클로저를 배우게 되면 (외부)함수가 종료되어도 외부함수의 변수가 내부함수에서는 살아 있는 예외적 경우는 있습니다. 알 수 없는 사용자 2019.4.11 21:47

1 답변

  • 좋아요

    2

    싫어요
    채택 취소하기
    a=0
    def vartest(a):
        a=1
        return a
    
    print(vartest(a))
    print(a)
    
    결과:
    1
    0
    

    질문자의 본 질문인 a 가 없다고 하는 이유는 vartest(a) 를 호출할 때 a라는 변수가 없는 상황이기 때문입니다. 즉 전역으로 설정한 a = 0 을 지우고 vartest(a) 를 호출하면 당연히 a변수가 없는 상황이기 때문에 a가 정의되지 않았다고 하는 겁니다.

    그런데 조금 더 나아가 위의 결과는 파이썬 프로그래밍을 할 때 중요한 포인트를 알려줍니다.

    질문자는 단순히 왜 에러가 발생하는지를 물었지만 사실 위의 질문에서 더 중요한 질문은 함수 호출뒤 a값이 왜 1이 아닌지 입니다.

    파이썬에서는 명시적인 call by reference 가 불가능합니다. 여기서 명시적이라는 의미는 c에서 & 같은 연산자가 없다는 의미입니다.

    다만 파이썬에서는 전달되는 파라미터 타입에 따라 call by value 혹은 call by reference 를 선택 적용하게 됩니다.

    구체적으로 int, float, tuple 같은 변경불가능한 객체는 call by value 로 전달됩니다. 즉 값을 복사합니다. 값만 복사하므로 원본 객체는 변함이 없습니다. 즉 위의 예에서 1로 변경을 해도 원본 a 객체는 변함없이 0 인 겁니다.

    그러나 list, dict 같은 변경가능한 객체들은 call by reference 로 전달이 됩니다. 레퍼런스가 전달되므로 함수에서 인자로 전달후 추가 혹은 삭제등의 변경을 하면 전달했던 원본 객체도 변하게 됩니다.

    • 상세한 답변 감사합니다. 다만 입문한지 얼마 되지 않아서 4번째 단락에서부턴 처음 들어보는 단어들이 많네요..ㅎㅎ 더 공부하다 이해가 좀 되었다 싶으면 다시 보겠습니다! limephan 2019.4.11 13:46
    • 아직 4번째 단락부턴 이해하지 못했지만 질문에 대해선 해결한 것 같습니다. 두 줄의 print()는 결국 print(vartest(0), print(0)을 한 것과 같은 게 맞는거죠? 전자의 경우 인수(argument) 0을 받아서 코드 블록대로 실행해 1을 출력했고 후자의 경우는 함수 밖의 변수 a에 0을 대입해 0을 출력한 것이었네요. limephan 2019.4.11 20:22

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

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

(ಠ_ಠ)
(ಠ‿ಠ)