"클로저"라는 용어는 함수형 프로그래밍에서 유래되었으며 파이썬에 도입된 지 오래되었습니다. 클로저는 함수가 생성된 환경을 기억할 수 있게 하여, 그 환경 밖에서 호출되더라도 유지되게 합니다. 이 개념은 유연성을 제공하며, 함수 팩토리 및 지연 계산과 같은 여러 패턴을 구현할 수 있게 합니다.
파이썬에서 함수는 1급 객체입니다. 때때로 내부 함수가 포함 함수의 범위에 있는 변수를 사용해야 하는 경우가 있습니다. 일반적인 렉시컬 범위는 함수가 반환될 때 이를 보장하지 않습니다. 만약 그러한 함수가 생성 환경의 변수를 참조하게 된다면 클로저가 발생합니다.
클로저는 내부 함수가 외부에서 정의된 변수를 참조하고, 그 외부 함수가 내부 함수를 외부로 반환할 때 발생합니다. 이는 함수 팩토리를 생성하거나, 클래스 없이 상태를 캡슐화하거나, "즉시" 파라미터를 가지는 함수를 구성할 때 자주 사용됩니다.
def make_multiplier(factor): def multiplier(x): return x * factor return multiplier mul2 = make_multiplier(2) mul3 = make_multiplier(3) print(mul2(10)) # 20 print(mul3(10)) # 30
nonlocal 키워드를 사용해야 합니다.클로저가 호출 간에 변경 가능한 상태를 유지할 수 있나요, 만약 변수가 내부 함수에서 변경된다면?
네, 내부 함수에서 nonlocal 키워드를 사용하면 가능합니다. nonlocal 없이 대입하면 새로운 지역 변수를 생성하여 외부 변수를 변경하지 않습니다.
def counter(): count = 0 def inc(): nonlocal count count += 1 return count return inc c = counter() print(c()) # 1 print(c()) # 2
클로저를 사용해 파이썬에서 클래스를 대신해 프라이빗 변수를 구현할 수 있나요?
네, 클로저는 외부에서 접근할 수 없는 "프라이빗" 변수를 단순하게 구현하는 방법을 제공합니다. 만약 내부 함수에 getter/setter가 제공되지 않는다면, 외부에서 접근할 수 없습니다.
클로저는 함수에만 적용되나요? 파이썬에서 람다를 사용해 클로저를 만들 수 있나요?
네, 클로저는 람다 표현식을 사용하여도 형성될 수 있으며, 이는 변수의 렉시컬 바인딩 면에서 def와 유사합니다.
def make_power(n): return lambda x: x ** n square = make_power(2) cube = make_power(3) print(square(4)) # 16 print(cube(2)) # 8
루프에서 핸들러를 형성하는 함수 팩토리는 루프 변수를 내부 클로저에서 사용하는 경우:
handlers = [] for i in range(3): def handler(x): return x + i handlers.append(handler) print([h(10) for h in handlers]) # [12, 12, 12]
장점:
단점:
디폴트 인자를 사용하여 "고정" 값을 설정:
handlers = [] for i in range(3): def handler(x, j=i): return x + j handlers.append(handler) print([h(10) for h in handlers]) # [10, 11, 12]
장점:
단점: