1. 변수의 사용 범위 알아보기
전역 변수(global variable)
함수를 포함하여 스크립트 전체에서 접근할 수 있는 변수를 전역 변수(global variable)라고 부릅니다. 특히 전역 변수에 접근할 수 있는 범위를 전역 범위(global scope)라고 합니다.
지역 변수(local variable)
변수 x는 함수 foo 안에서 만들었기 때문에 foo의 지역 변수(local variable)입니다. 따라서 지역 변수는 변수를 만든 함수 안에서만 접근할 수 있고, 함수 바깥에서는 접근할 수 없습니다. 특히 지역 변수를 접근할 수 있는 범위를 지역 범위(local scope)라고 합니다.
x = 10 # 전역 변수
def foo():
print(x) # 전역 변수 출력
foo()
print(x) # 전역 변수 출력
10
10
그럼 변수 x를 함수 foo 안에서 만들면 어떻게 될까요?
def foo():
x = 10 # foo의 지역 변수
print(x) # foo의 지역 변수 출력
foo()
print(x) # 에러. foo의 지역 변수는 출력할 수 없음
10
Traceback (most recent call last):
File "C:\project\local_variable.py", line 6, in <module>
print(x) # 에러. foo의 지역 변수는 출력할 수 없음
NameError: name 'x' is not defined
2. 함수 안에서 전역 변수 변경하기
만약 함수 안에서 전역 변수의 값을 변경하면 어떻게 될까요?
x = 10 # 전역 변수
def foo():
x = 20 # x는 foo의 지역 변수
print(x) # foo의 지역 변수 출력
foo()
print(x) # 전역 변수 출력
20
10
함수 안에서 전역 변수의 값을 변경하려면 global 키워드를 사용해야 합니다. 다음과 같이 함수 안에서 global에 전역 변수의 이름을 지정해줍니다.
- global 전역변수
x = 10 # 전역 변수
def foo():
global x # 전역 변수 x를 사용하겠다고 설정
x = 20 # x는 전역 변수
print(x) # 전역 변수 출력
foo()
print(x) # 전역 변수 출력
20
20
함수 안에서 변수를 global로 지정하면 전역 변수를 사용하게 됩니다.
만약 전역 변수가 없을 때 함수 안에서 global을 사용하면 해당 변수는 전역 변수가 됩니다.
# 전역 변수 x가 없는 상태
def foo():
global x # x를 전역 변수로 만듦
x = 20 # x는 전역 변수
print(x) # 전역 변수 출력
foo()
print(x) # 전역 변수 출력
파이썬에서 변수는 네임스페이스(namespace, 이름공간)에 저장됩니다.
다음과 같이 locals 함수를 사용하면 현재 네임스페이스를 딕셔너리 형태로 출력할 수 있습니다.
전역 범위
>>> x = 10
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'x': 10}
지역 범위
>>> def foo():
... x = 10
... print(locals())
...
>>> foo()
{'x': 10}
3. 함수 안에서 함수 만들기
이번에는 함수 안에서 함수를 만드는 방법을 알아보겠습니다. 다음과 같이 def로 함수를 만들고 그 안에서 다시 def로 함수를 만들면 됩니다.
def 함수이름1():
코드
def 함수이름2():
코드
간단하게 함수 안에서 문자열을 출력하는 함수를 만들고 호출해봅니다.
def print_hello():
hello = 'Hello, world!'
def print_message():
print(hello)
print_message()
print_hello()
Hello, world!
지역 변수의 범위
def print_hello():
hello = 'Hello, world!'
def print_message():
print(hello) # 바깥쪽 함수의 지역 변수를 사용
4. 지역 변수 변경하기
지금까지 바깥쪽 함수의 지역 변수를 안쪽 함수에서 사용해봤습니다. 그럼 바깥쪽 함수의 지역 변수를 안쪽 함수에서 변경하면 어떻게 될까요?
def A():
x = 10 # A의 지역 변수 x
def B():
x = 20 # x에 20 할당
B()
print(x) # A의 지역 변수 x 출력
A()
10
현재 함수의 바깥쪽에 있는 지역 변수의 값을 변경하려면 nonlocal 키워드를 사용해야 합니다. 다음과 같이 함수 안에서 nonlocal에 지역 변수의 이름을 지정해줍니다.
- nonlocal 지역변수
def A():
x = 10 # A의 지역 변수 x
def B():
nonlocal x # 현재 함수의 바깥쪽에 있는 지역 변수 사용
x = 20 # A의 지역 변수 x에 20 할당
B()
print(x) # A의 지역 변수 x 출력
A()
20
이제 함수 B에서 함수 A의 지역 변수 x를 변경할 수 있습니다. 즉, nonlocal은 현재 함수의 지역 변수가 아니라는 뜻이며 바깥쪽 함수의 지역 변수를 사용합니다.
nonlocal이 변수를 찾는 순서
nonlocal은 현재 함수의 바깥쪽에 있는 지역 변수를 찾을 때 가장 가까운 함수부터 먼저 찾습니다. 이번에는 함수의 단계를 A, B, C로 만들었습니다.
def A():
x = 10
y = 100
def B():
x = 20
def C():
nonlocal x
nonlocal y
x = x + 30
y = y + 300
print(x)
print(y)
C()
B()
A()
50
400
global로 전역 변수 사용하기
특히, 함수가 몇 단계든 상관없이 global 키워드를 사용하면 무조건 전역 변수를 사용하게 됩니다.
x = 1
def A():
x = 10
def B():
x = 20
def C():
global x
x = x + 30
print(x)
C()
B()
A()
31
5. 클로저 사용하기
함수를 둘러싼 환경(지역 변수, 코드 등)을 계속 유지하다가, 함수를 호출할 때 다시 꺼내서 사용하는 함수를 클로저(closure)라고 합니다. 여기서는 c에 저장된 함수가 클로저입니다.
클로저를 사용하면 프로그램의 흐름을 변수에 저장할 수 있습니다. 즉, 클로저는 지역 변수와 코드를 묶어서 사용하고 싶을 때 활용합니다. 또한, 클로저에 속한 지역 변수는 바깥에서 직접 접근할 수 없으므로 데이터를 숨기고 싶을 때 활용합니다.
def calc():
a = 3
b = 5
def mul_add(x):
return a * x + b # 함수 바깥쪽에 있는 지역 변수 a, b를 사용하여 계산
return mul_add # mul_add 함수를 반환
c = calc()
print(c(1), c(2), c(3), c(4), c(5))
8 11 14 17 20
lambda로 클로저 만들기
def calc():
a = 3
b = 5
return lambda x: a * x + b # 람다 표현식을 반환
c = calc()
print(c(1), c(2), c(3), c(4), c(5))
8 11 14 17 20
보통 클로저는 람다 표현식과 함께 사용하는 경우가 많아 둘을 혼동하기 쉽습니다. 람다는 이름이 없는 익명 함수를 뜻하고, 클로저는 함수를 둘러싼 환경을 유지했다가 나중에 다시 사용하는 함수를 뜻합니다.
클로저의 지역 변수 변경하기
지금까지 클로저의 지역 변수를 가져오기만 했는데, 클로저의 지역 변수를 변경하고 싶다면 nonlocal을 사용하면 됩니다. 다음은 a * x + b의 결과를 함수 calc의 지역 변수 total에 누적합니다.
def calc():
a = 3
b = 5
total = 0
def mul_add(x):
nonlocal total
total = total + a * x + b
print(total)
return mul_add
c = calc()
c(1)
c(2)
c(3)
8
19
33
.
[ 연습문제 1 ]
def counter():
i = 0
def count():
nonlocal i
i += 1
return i
return count
c = counter()
for i in range(10):
print(c(), end=" ")
1 2 3 4 5 6 7 8 9 10
[ 연습문제 2 ]
10 9 8 7 6 5 4 3 2 1
def countdown(n):
result = n
def func():
nonlocal result
result -=1
return result +1
return func
n = int(input())
c = countdown(n)
for i in range(n):
print(c(), end=" ")
'BASIC' 카테고리의 다른 글
2차원 리스트 (0) | 2023.11.24 |
---|---|
일급 객체 / switch (0) | 2023.11.24 |
람다 표현식(lambda expression) (1) | 2023.11.22 |
재귀호출 (0) | 2023.11.21 |
함수 (1) | 2023.11.19 |
댓글