처음코딩 파이썬 13 지역별, 전역변수

0
45


함수가 전역변수를 수정해야 하는 대표적인 상황으로 함수의 실행 결과를 누적해야 하는 경우가 있다. 다음은 쿠폰 도장이 찍힌 횟수를 전역변수에 기록하고 화면에 출력하는 stamp() 함수다.

코드 3-12 함수 안에서 전역변수를 수정하려는 오류

num_stamp = 0  # 쿠폰 스탬프가 찍힌 횟수 (전역변수)

def stamp():
    """쿠폰 스탬프가 찍힌 횟수를 증가시키고, 화면에 출력한다."""
    num_stamp = num_stamp + 1  # ❶ 전역변수를 수정하려고 시도함
    print(num_stamp)

실행 결과:

UnboundLocalError: local variable 'num_stamp' referenced before assignment

이 함수를 실행하면 ❶에서 오류가 발생한다. “지역 변수 num_stamp에 값을 대입하기도 전에 참조했다”라는 오류 메시지가 출력된다.

오류가 발생한 과정을 생각해 보자. num_stamp = 값을 대입할 때, 함수 안에서는 num_stamp라는 새로운 지역변수가 생성된다. 그런데 num_stamp에 대입할 값이 공교롭게도 num_stamp + 1이다. 아직 만들어지지 않은 지역변수를 읽으려 한 것이다.

원래 의도는 전역변수 num_stamp의 값을 읽으려는 것이었다. 하지만 함수 안에서 num_stamp에 무언가를 대입하려 했기 때문에 이 변수는 지역변수로 해석되었다. 함수 안에서는 지역변수에만 값을 대입할 수 있기 때문이다.

이 문제를 해결하려면 global 문을 이용해 num_stamp 변수가 전역변수임을 명시적으로 밝혀야 한다.

global 문

global 문을 사용하면 함수 안에서도 전역변수의 값을 수정할 수 있다. 함수 안에서 global 변수이름 명령을 실행하면 그 이름이 전역변수임을 분명히 밝히게 되며, 그리고 전역변수의 값을 수정하는 것도 가능해진다. stamp() 함수에 global 문을 삽입해 수정해 보자.

코드 3-13 global 문의 사용

num_stamp = 0  # 쿠폰 스탬프가 찍힌 횟수 (전역변수)

def stamp():
    """쿠폰 스탬프가 찍힌 횟수를 증가시키고, 화면에 출력한다."""
    global num_stamp           # ❶ num_stamp는 전역변수다
    num_stamp = num_stamp + 1  # 이제 오류가 발생하지 않는다
    print(num_stamp)

stamp()  # 화면에 1이 출력된다
stamp()  # 화면에 2가 출력된다

실행 결과:

1
2

❶의 global 문을 실행함으로써 함수 안에서도 함수 밖의 전역변수 num_stamp를 수정할 수 있게 되었다. 원래 의도한 함수를 만드는 데 성공했다.

global 문은 사용하지 않는 것이 좋다

global 문을 배웠지만, 역시 이 명령은 사용하지 않는 것이 좋다. global 문을 사용하는 것은 함수가 매개변수와 반환값을 이용해 외부와 소통하는 자연스러운 흐름을 깨트리는 일이다.

함수 안에서 전역변수를 수정하지 않고, 매개변수와 반환값만 이용하더라도 함수의 실행 결과를 누적하는 데 부족함이 없다. 다음 예제는 전역변수를 직접 수정하는 대신, 매개변수와 반환값을 이용하도록 stamp() 함수를 수정한 버전이다.

코드 3-14 매개변수와 반환을 이용한 stamp() 함수

num_stamp = 0  # ❶ 쿠폰 스탬프가 찍힌 횟수 (전역변수)

def stamp(num_stamp):  # ❷ 지역변수(매개변수) num_stamp
    """쿠폰 스탬프가 찍힌 횟수를 증가시키고, 화면에 출력한다."""
    num_stamp = num_stamp + 1
    print(num_stamp)
    return num_stamp

num_stamp = stamp(num_stamp)  # ❸ 전역변수에 함수의 반환값을 대입한다
num_stamp = stamp(num_stamp)

실행 결과:

1
2

위 코드에는 두 개의 num_stamp 변수가 등장한다. 하나는 ❶ 전역변수 num_stamp이고, 다른 하나는 ❷ 좌변의 stamp() 함수의 지역변수이자 매개변수인 num_stamp다. 두 변수는 이름은 같지만 (이름을 다르게 지어도 된다) 존재하는 공간이 다르기 때문에, 서로 전혀 다른 변수다. stamp() 함수는 자신의 지역변수인 num_stamp만을 수정하고, 전역변수 num_stamp는 건드리지 않는다. 전역변수 num_stamp는 함수 밖(❸)에서만 수정되고 있다.

이처럼 함수 안에서 전역변수를 수정하지 않아도 함수의 실행 결과를 누적할 수 있다. 다른 사람의 프로그램을 읽을 수 있도록 global 문의 사용법을 알아두되, 가급적이면 사용하지 않도록 하자.

댓글 남기기

쉽고 친절한 책을 위해 원고 내용 일부를 공개하고 독자의 의견을 받고 있습니다. 글을 읽고 모르겠는 점, 어려운 점, 또는 틀린 점을 알려주시면 도움을 주실 수 있습니다.