본문 바로가기
Language/Python

[Python] Scope에 대한 이해

by 며루치꽃 2021. 11. 10.

모듈은 전역 이름공간을 가지고 있어서 모듈 내부에 작성된 함수나 클래스가 이름공간에 정의된 변수를 참조할 수 있다. 모듈에 정의된 함수는 지역 이름공간을 가지고 있어서 이 함수 내부에 또 함수를 정의하면 지역 이름공간이 만들어진다. 이렇게 이름공간에 있는 변수를 참조하여 범위를 정하는 규칙을 스코프(scope)라고 한다. 스코프에 따라 변수를 참조할 수 있어 규칙을 벗어나면 예외가 발생한다. 

 

1. 지역변수를 할당 없이 처리


함수 func를 정의할 때 매개변수는 x, y 2개 이고 내부에 변수 result에 더한다. 모두 3개의 지역변수가 만들어진다. 

def func(x, y): #에러
	result = result + x + y
	return result

함수에 2개의 인자를 넣고 실행하면 예외가 발생한다. 함수 내부에 정의된 result 지역변수가 두 매개변수와 더할 때 변숫값을 가져오지 못해서 예외가 발생한다. 예외가 발생하는 이유는 result를 변수에 할당하지 않고 내부적으로 인식해 result를 지역 이름공간에서만 찾기 때문이다. 

변수를 사용하려면 먼저 변수에 값을 할당해야 한다. 그 다음에 변수를 참조하거나 할당한다.

 

def func(x, y):
    result = 0
    result = result + x + y
    return result

2. 전역변수 이용하기

 

전역변수는 모듈에 정의되어 전역 이름공간에 저장되어 있는 변수이다.

전역 변수 result를 할당하고 위에서 작성한 함수와 같은 로직을 그대로 작성해 실행하면 예외가 발생한다. 표현식에 있는 result가 전역 이름공간에 있어서 참조할 것 같지만, 실제는 참조하지 못한다. 이유는 같은 이름의 변수가 할당되어서 지역 이름공간을 먼저 찾기 때문이다.

 

result = 0

def func(x, y):
    result = result + x + y #에러
    return result

이런 문제를 해결하기 위해서는 사용하는 변수가 어느 이름공간에 있는지 먼저 지정해야한다. 이때 global과 전역변수 이름을 먼저 선언해서 전역변수를 참조할 수 있도록 만들어야한다.

 

result = 0

def func(x, y):
    global result
    result = result + x + y
    return result

 

3. 지역 이름 공간이 계층화된 경우 참조 알아보기

 

def outer1(x, y):
    def inner1(): #에러
        x = x + 1
        return x
    return inner1()

outer1()

내부 함수에 같은 이름의 변수를 계산하고 그 이름의 변수에 할당하여 실행하면 x 가 없다고 나온다. 변수 할당 없이 같은 변수에 특정 값을 계산한 결과를 할당하면 항상 지역 이름공간에 변수가 있는지 확인해서 발생하는 문제이다.

이 문제를 해결하려면 먼저 내부 함수에 지역변수 x를 할당해야 한다. 

 

def outer1(x, y):
    def inner1():
        x = 0
        x = x + 1
        return x
    return inner1()

outer1()

 

이번엔 외부 함수에 변수 x를 할당했다. 내부 함수에서도 변수 x를 사용한 예제는 다음과 같다. 

def outer2(x, y): 
    x = 0
    def inner2():
        x = x + 1 #에러
        return x
    return inner2()

outer2()

이런 문제를 해결하려면 외부 함수에 선언된 변수 x를 내부 함수에서 사용한다는 표시인 nonlocal을 변수 이름 앞에 정의해야한다. 

 

# nonlocal 
def outer2(x, y): 
    x = 0
    def inner2():
        nonlocal x
        x = x + 1 
        return x
    return inner2()

outer2()

 

외부 함수 변수에 x에 빈 리스트를 할당하고 내부 함수 변수 x에 원소를 추가하는 예제이다.

def outer3(x, y):
    x = []
    def inner3():
        x = x.append(5)
        return x
    return inner3()

 outer3()

내부 함수에 할당문이 있으면 먼저 할당될 변수를 인식해서 예외가 발생한다. 변경할 수 있는 리스트는 어디서나 객체를 추가할 수 있다. 그래서 내부 함수의 변수 할당을 없애면 리스트 객체에 원소를 추가할 수 있다. 그래서 내부 함수의 변수 할당을 없애면 리스트 객체에 원소를 추가한 값을 반환한다. 

def outer3(x, y):
    x = []
    def inner3():
        x.append(5)
        return x
    return inner3()

 

 

댓글