Re: 33.3.2 클로저 구문 도중 중첩함수 리턴문관련 질문드립니다.
, 도장_ 관리자님이 작성Unit 33.3.2의 예제를 실행합니다.
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)
print('----------')
d = calc()
d(1)
실행결과는 다음과 같습니다.
8 19 33 ---------- 8
질문에서
c1(2)는 = clac2(2)와 같은데...
라고 하셨는데, 아닙니다.
클로저는 함수의 별칭이 아닙니다.
이게 함수의 별칭입니다.
>>> pp = print
>>> pp('hello')
hello
>>>
함수 클로저는 먼저 함수 클로저를 생성하는 과정을 거칩니다.
c = calc()
d = calc()
이 과정은 함수 클로저를 생성하는 과정입니다.
c에는 c만의 함수 클로저 공간이 생성되고, 이 함수 클로저에 생성된 변수는 c만의 함수 클로저 공간에서만 접근할 수 있고, 유효합니다.
d에는 d만의 함수 클로저 공간이 생성되고, 이 함수 클로저에 생성된 변수는 d만의 함수 클로저 공간에서만 접근할 수 있고, 유효합니다.
Unit 33을 보시면
함수 안에서의 지역 변수
함수 안에서의 전역 변수
함수 안에서 함수를 만들었을 때, 내부 함수의 지역 변수
그리고 접근 범위를 위해 사용하는 nonlocal, global 키워드
클로저의 지역 변수로 내용이 이어집니다.
각 범위와 각 범위에서 유효한 변수를 이해할 필요가 있습니다.
Unit 33을 정독하거나 여러 차례 반복하는 게 이해에 더 도움이 될 겁니다.
본문의 설명을 보면
잘 보면 함수 calc가 끝났는데도 c는 calc의 지역 변수 a, b를 사용해서 계산을 하고 있습니다. 이렇게 함수를 둘러싼 환경(지역 변수, 코드 등)을 계속 유지하다가, 함수를 호출할 때 다시 꺼내서 사용하는 함수를 클로저(closure)라고 합니다. 여기서는 c에 저장된 함수가 클로저입니다.
함수는 본래 호출과 함께 모든 내용이 사라집니다. 함수 호출이 끝나면 함수 범위의 모든 내용이 사라집니다. 클로저는 변수 선언을 통해 클로저를 위한 메모리 공간을 할당합니다. 파이썬 내부에서는 이를 셀 객체(cell object)라고 부릅니다.
c = calc()라고 호출한 다음에는 c.__closure__로 확인할 수 있고, c.__closure__[0].cell_contents로 내부를 확인할 수 있습니다.
c = calc() 과정을 생략하고, calc(1), calc(2)처럼 호출하는 과정은 성립하지 않습니다.
calc(1) 호출은 에러만 발생할 뿐입니다.
Traceback (most recent call last): File "/tmp/027375125/main.py", line 11, in <module> calc(1) TypeError: calc() takes 0 positional arguments but 1 was given
calc(1)이 에러가 발생하는 것은 인수를 받지 않는 데 인수가 있기 때문입니다.
calc() 호출로 클로저를 생성해야 하기 때문에 클로저 생성에서는 인수가 없습니다.
calc 클로저에는 mul_add(x) 함수를 생성해서 반환하는 코드이므로
c = calc() 호출 이후에는 c에는 생성된 mul_add(x) 함수를 참조하게 됩니다.
pp = print와 같은 상태인 것이죠. 그래서 c(1)은 인수를 받을 수 있고, 동작하게 됩니다.
클로저를 생성하는 c = calc() 과정을 생략하고 calc(1)을 아무리 호출해도 동작하지 않습니다. calc()는 인수를 받지 않는 함수로 선언되어 있으니까요.