파이썬을 사용하다보면 함수를 정말 많이 만들게 된다. 특히 협업할 때는 수행할 일을 명확하게 전해주기 위해 인풋과 아웃풋을 알려주고 그것을 수행하는 함수를 작성하게 된다.
이렇게 함수를 작성하다보면 변수 영역이 상당히 중요하다. 전역 변수인지, 로컬 변수인지, 데코레이터 형식에서 사용되는 로컬 변수는 어떻게 다룰지 등등..
중요한건 몰라도 잘 구현하지만 좋은 코드가 아니라는 점이다. 어떻게 보면 간단하고 명확하게 알지 않아도 구현하는데 어려움이 없는 개념이기에 지나치기 쉽고 안좋은 코딩 방식이 고착화될 가능성이 높다고 생각되는 부분이다.
때문에 변수의 영역에 대해 깊지 않지만 정확하게 짚기 위한 포스터를 작성해본다.
전역 변수는 특정 함수나 클래스가 아닌 스크립트 영역에 선언된 변수로 어느 영역에서든 접근이 가능하다.
지역 변수는 당연히 해당 영역에서만 사용 가능하다.
다른 언어에서는 전역, 지역 변수의 이름이 겹친다면 지역 후 전역 변수를 사용하지만 파이썬에서는 global
이라는 명확한
var = 10
print(var) # 10
def fn():
var = 20
print(var) # 20
def gn():
print(var) # Error
def foo():
global var
var += 100
print(var) # 110
global
로 가져온 변수는 전역변수를 읽고 수정까지 할 수 있지만 pythonic한 코드도 아니고 권장되는 코드 스타일도 아니다. 전역 변수를 특정 부분에서 수정한다면 다른 곳에서 전역 변수를 사용할 때 영향을 받기 때문이다.
전역 변수는 주로 변하지 않는 고정 값에 사용하는 것이 옳다.
개인적으로
global
을 쓴 경험이 있긴했다.
FastAPI에서 딥러닝 모델을 사용하는데 GPU에 단 한 번만 올려놓아야 하는 상황이였다.
model=None
을 전역변수로 선언하고- FastAPI가 실행될 때
model=DLModel()
로 초기화- 다른 코드에서 해당 모델을 가져와서 사용
Closure 형식에서는 nonlocal
이 사용될 수 있다.
스코프 내의 하위 스코프가 있을 때, 하위 스코프가 상위 스코프의 지역 변수를 사용할 수 있는 방법이다.
Closure
어떤 함수의 내부 함수가 외부 함수의 변수를 참조할 때, 외부 함수가 종료되어도 내부 함수가 외부 함수의 변수를 참조할 수 있도록 어딘가에 저장하는 함수
조건
- 어떤 함수의 내부 함수일 것
- 내부 함수가 외부 함수의 변수를 참조할 것
- 외부 함수가 내부 함수를 리턴할 것
def outer(number):
a = number
def inner():
nonlocal a
a += 200
print(a)
return inner
f = outer(100)
f() # 300
f() # 500
f() # 700
f() # 900
변수에 접근하려면 locals
, globals
가 있다.
각각 지역변수, 전역변수를 딕셔너리 형태로 저장하고 있고 key값은 str
타입으로 저장되어 있다.
def fn(number):
x = 10
def printt():
print("Inner func")
print(locals())
return printt
func = fn(100)
func()
# Inner func
# {'number': 100, 'x': 10, 'printt': <function fn.<locals>.printt at 0x00000193734C1840>}
여기서 알 수 있듯이 함수의 인자는 지역 변수로 들어간다.
globals
도 마찬가지이고 파이썬 내부적으로 다음 두 코드는 같은 코드로 볼 수 있다.
a = 100
globals()['a'] = 100