티스토리 뷰

군대에는 총을 보관하는 총기함이란 것이 있습니다. 늘 총을 휴대할 수는 없기 때문에 총이 필요한 경우가 아니라면 총기함에 보관하는데, 초소에 경계근무를 나갈 때에는 자신의 총을 꺼내서 가져갑니다. 총은 무척 위험하면서도 중요한 무기이기 때문에 항상 위치를 파악하고 있어야 합니다. 만약 분실사고라도 생긴다면 온 부대가 벌컥 뒤집혀지지요.

 

어느 부대의 총기함에 총이 10자루가 있고 2명이 경계근무를 나가는 과정에서 남은 총을 구하는 예제를 만들어 보겠습니다. 다음 코드를 실행했을 때 남은 총은 몇 자루가 될까요?

gun = 10 # 총 10자루

def checkpoint(soldiers): # 경계근무 나가는 군인 수
    gun = gun - soldiers # 전체 총에서 경계근무 나가는 군인 수만큼 뺀 잔여 총
    print("[함수 내] 남은 총 : {0}".format(gun))

print("전체 총 : {0}".format(gun)) # 10 자루
checkpoint(2) # 2명이 경계 근무 출발
print("남은 총 : {0}".format(gun)) # 몇 자루?

 

정답은, "에러가 발생한다" 입니다.

UnboundLocalError: local variable 'gun' referenced before assignment

에러 메시지를 보면 'gun' 이라는 변수는 아직 할당도 되지 않았는데 사용되었다고 하네요. 분명 코드 초반부에 10 이라는 값으로 변수 선언을 했는데 왜 이런 문제가 생겼을까요?

 

함수를 이용할 때 꼭 알아야 하는 개념이 있습니다. 바로 지역변수와 전역변수인데요. 지역 변수란 함수 내에서만 쓸 수 있는 변수이며, 전역 변수는 모든 곳에서 쓸 수 있는 변수입니다. 그리고 checkpoint() 함수 내에서 사용하려는 gun 은 함수 외부에 선언된 gun 과는 아무 상관 없는, checkpoint() 함수 내에서 새로 만들어진 지역변수입니다. 아직 아무 값도 들어가지 않고 gun 이 선언되지도 않았는데 gun - soldiers 라는 연산을 하려다보니 에러가 발생한 것이죠.

 

checkpoint() 함수 내에 변수를 선언하는 부분을 추가해보겠습니다. 확인을 위해서 일부러 20 이라는 값을 넣어볼게요.

gun = 10 

def checkpoint(soldiers):
    gun = 20 # 변수 선언 추가
    gun = gun - soldiers
    print("[함수 내] 남은 총 : {0}".format(gun))

print("전체 총 : {0}".format(gun))
checkpoint(2)
print("남은 총 : {0}".format(gun))

 

다행히 에러는 나지 않네요. 실행 결과는 이렇습니다.

전체 총 : 10
[함수 내] 남은 총 : 18
남은 총 : 10

전체 총과 남은 총은 10 으로 변함이 없고 checkpoint() 함수 내에서 새롭게 선언된 gun 에는 20 이라는 값이 저장되었다가 군인 수만큼 2를 빼니 18 로 줄어들었네요. 하지만 실제로 총기함에는 2자루의 총이 줄어든 8자루라고 나와야 정상이겠죠?

 

해결책은 바로 global 이라는 키워드입니다. 함수 내에서 전역변수를 사용하겠다는 의미인데요. global gun 이라고만 하면 전역 공간에 선언된 변수를 그대로 사용하며 그 값을 직접 변경할 수도 있습니다.

 

gun = 10

def checkpoint(soldiers):
    global gun # 전역공간에 있는 gun 이라는 변수를 사용
    gun = gun - soldiers
    print("[함수 내] 남은 총 : {0}".format(gun))

print("전체 총 : {0}".format(gun))
checkpoint(2)
print("남은 총 : {0}".format(gun))

 

이제는 총기함에 남은 총의 올바른 값을 확인할 수 있습니다.

전체 총 : 10
[함수 내] 남은 총 : 8
남은 총 : 8

 

하지만 전역변수를 많이 쓰게 되면 코드 관리가 어려워질 수 있으므로 필요한 경우에는 물론 써야하겠지만 꼭 필요한 경우가 아니라면 가급적 사용하지 않는 편을 권해드립니다.

 

앞에서 작성한 코드를 전역변수가 없는 버전으로 만들어 보겠습니다. 전달값과 반환값을 적절히 활용하는 방법이며, 반환(return) 을 의미하는 내용을 담아 checkpoint_ret() 라는 새로운 함수로 정의하겠습니다.

gun = 10

def checkpoint_ret(gun, soldiers): # 전체 총 수와 군인 수를 전달받음
    gun = gun - soldiers # 전달받은 gun 을 사용
    print("[함수 내] 남은 총 : {0}".format(gun))
    return gun

print("전체 총 : {0}".format(gun))
gun = checkpoint_ret(gun, 2) # gun 값을 함수에 전달
print("남은 총 : {0}".format(gun))

함수를 정의할 때 가급적 외부 상황은 몰라도 되도록 전달받은 값만 이용하게끔 작성하면 보다 간결하면서도 함수의 역할에 충실할 수 있습니다. 그리고 잘 만들어둔 함수는 언젠가 다른 소스코드에서 필요한 경우에 그대로 복사하면 바로 사용할 수도 있게 되지요.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함