변수 범위 variable scope (python)
앞서 병렬처리 부분에서 클로저의 개념을 다루기 전에 변수 범위를 간단하게 다루었는데, 이번에 본격적으로 개념을 정리하고자 한다
전역변수
전역변수는 주로 변하지 않는 상수값 또는 고정값을 가진 변수로 사용하는 것이 일반적이다
a = 10 # Global variable
def foo():
# Read global variable
print(a)
foo() # 10
print(a) # 10
지역변수
지역변수는 함수 내에 로직 해결에 국한되고, 함수 실행 해제 시 소멸되는 특징을 가진다
따라서, 용도와 다르게 global
keyword 를 활용하여 전역변수를 지역내에서 수정하는 것은 권장되지 않고 있다
(아래에서 global
keyword 에 대해 정리하였다)
b = 20
def bar():
b = 30 # Local variable
print(b) # Read local variable
bar() # 30 (local variable - b)
print(b) # 20 (global variable - b)
global keyword 의 사용
전역변수에 대해 함수 내에서 단순히 할당 또는 수정을 시도하면 UnboundLocalError 이 발생하게 된다
c = 40
def foobar():
# c = c + 10 # UnboundLocalError
# c = 10
# c += 100
print(c)
foobar()
에러없이 전역변수를 함수내에서 할당하거나 수정하려면 global
키워드로 전역변수로 명시하면 가능하다
그러나, 이러한 사용은 권장되지 않음 (변수 범위를 벗어난, 직관적이지 않은 사용이므로 혼란을 야기할 수 있기 때문이다)
# Ex4
d = 50
def barfoo():
global d
d = 60
print(d)
barfoo() # 60
print(d) # 60
nonlocal keyword 의 사용
클로저 형태로 만들어진 함수 내부의 함수가, 지역함수를 수정하거나, 참조하려면 nonlocal
키워드를 사용한다
이 때, 클로저의 자유변수로서, 값의 마지막 상태가 저장된채로 계속 갱신된다
def outer():
e = 70
def inner():
nonlocal e
e += 10 # e = e + 10
print(e)
return inner
in_test = outer() # Closure
in_test() # 80
in_test() # 90
함수 내에서 지역변수를 포함한 namespace를 출력하려면 locals()
를 활용할 수 있다
def func(var):
x = 10
def printer():
print("Printer Func Inner")
print('Func Inner', locals()) # 함수 내 namespace 출력
func("Hi") # Func Inner {'var': 'Hi', 'x': 10, 'printer': <function func.<locals>.printer at 0x000001D8B6E265E0>}
전역에서도 전역변수를 포함한 namespace를 출력하려면 globals()
를 활용할 수 있다. globals()
와 locals()
는 모두 dict type 으로 속성명과 값을 관리하고 있다. globals()
가 dict type인 것을 활용하여 아래와 같이 전역 변수를 정의할 수도 있다 (test_variable
)
print(globals()) # { '__name__': '__main__', .... }
globals()['test_variable'] = 100
print(globals()) # { '__name__': '__main__', .... , 'test_variable': 100 }
globals()
를 활용하여 반복문을 통해 자동으로 값을 원하는 변수명으로 할당하여 전역 변수를 정의할 수 있다
for i in range(1, 10):
for k in range(1, 10):
globals()[f'plus_{i}_{k}'] = i + k
print(plus_3_5) # 8
print(plus_9_9) # 18