[python] Closure (클로저)

gunny·2025년 2월 12일
0

Python

목록 보기
32/35

클로저(Closure)

  • 클로저는 함수형 프로그래밍에서 중요한 개념이다.
  • 내부 함수가 자신이 선언될 당시의 환경을 기억하고 사용하는 기능이다.
  • python에서도 클로저를 사용할 수 있는데, 즉, 함수가 생성될 때 변수 값(상위 함수의 변수들)을 기억하고, 그 함수 외부에서 해당 값들을 사용할 수 있는 특징을 가진다.
    즉, 함수가 선언될 때의 자유 변수(free variable)을 참조하는 내부함수이다.

클로저의 특징

  • 외부 함수의 변수를 참조하는 내부 함수이다.
  • 내부 함수는 외부 함수의 변수에 접근할 수 있지만, 외부 함수가 종료된 후에도 그 변수를 기억한다.
  • 외부 함수는 호출이 끝났더라도 내부 함수는 외부 함수의 변수를 참조할 수 있다.

클로저 관련 예시 코드 (1)

def outer_function(outer_variable): # 외부 함수
    def inner_function(inner_variable): # 내부 함수
        return outer_variable + inner_variable

    return inner_function #내부 함수를 반환

# 클로저 생성
closure = outer_function(10) # outer_function의 반환 값은 inner_function

# 클로저 호출
result = closure(5)
print(result) #15
  • outer_function 이 실행되면 inner_function 이 반환된다.
    이때 inner_functionouter_variable을 기억하고 있다.
    closure는 이제 inner_function을 참조하게 되며, outer_functionouter_variable 값을 기억하고 있다.
  • closure(5)를 호출하면, inner_functionouter_variable (값 10)과 inner_variable (값 5)을 합산하여 결과를 반환한다.
  • 이때 outer_function이 종료되었음에도 불구하고 closure는 outer_variable 값을 기억하는 클로저로 동작한다.

클로저가 유용한 이유

[1] 상태 유지

  • 클로저를 사용하면 외부 함수의 상태를 기억할 수 있기 때문에, 함수 호출 간에 상태를 저장하고 활용할 수 있다. 외부 함수의 변수를 지속적으로 활용해야 하는 상황에서 유용하다.

[2] 데이터 은닉

  • 클로저는 내부 함수가 외부 함수의 변수를 사용할 수 있도록 하므로, 외부에서 직접 접근할 수 없는 변수나 데이터를 간접적으로 다룰 수 있게 해준다.
    이렇게 함으로써 캡슐화(encapsulation)을 구현할 수 있다.

[3] 함수형 프로그래밍 패러다임

  • 클로저는 함수형 프로그래밍에서 중요한 역할을 하며, 함수 반환 값으로 다른 함수를 제공하는 방식으로 설계된 코드에서 매우 유용하다.

클로저 관련 예시 코드 (2)

  • 클로저를 활용한 팩토리 함수의 예이다.
    (팩토리 함수는 함수가 함수를 반환하는 방식)

def make_multiplier(factor):
    def multiplier(number):
        return number * factor
    return multiplier

# 팩토리 함수 사용
double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5)) # 10
print(triple(5)) # 15
  • make_multiplier는 인자 factor를 받아서, multiplier라는 내부 함수를 반환한다.
    -doubletriple은 각각 make_multiplier에서 반환된 함수이다.
  • double(5)는 2를 곱한 결과인 10을, triple(5)는 3을 곱한 결과인 15를 반환한다. 이때 doubletriple은 각각 다른 환경을 기억하는 클로저이다.

클로저 관련 예시 코드 (3)

  • 비밀번호 검증 시스템 (데이터 은닉과 상태 유지)
  • 클로저를 사용해 비밀번호 숨기고, 사용자가 올바른 비밀번호를 입력할 때만 접근할 수 있는 시스템 구현
def password_manager(correct_password):
    #상태 저장 함수
    _password = correct_password
    
    def check_password(input_password):
        if input_password == _password:
            return "Access granted"
        else:
            return "Access denied"
        
    return check_password

# 클로저 생성
password_checker = password_manager("my_secure_password")

# 비밀번호 입력
print(password_checker("wrong_password"))
print(password_checker("my_secure_password"))
  • password_manager 함수는 correct_password를 받아 비밀번호를 저장하는 클로저를 반환한다.
    이때 _password는 외부에서 직접 접근할 수 없고, 내부 함수 check_password_password에 접근할 수 있다.
    password_checker는 클로저로, 내부적으로 비밀번호를 저장하고 사용자가 입력한 비밀번호를 검증하는 역할을 한다.

  • 상태 유지: password_checker는 비밀번호 상태를 기억하고, 외부에서는 이를 변경할 수 없다.

  • 데이터 은닉: _password는 클로저 내에서만 접근 가능하고 외부에서는 직접적으로 변경할 수 없다.

장점

  • 상태 유지: 사용자가 클로저를 호출할 때마다 이전 상태를 기억하고, 비밀번호와 같은 중요한 데이터를 보호할 수 있다.
  • 데이터 은닉: 클로저 내에 데이터를 은닉하여, 외부에서 접근할 수 없도록 보호할 수 있다. password_checker는 비밀번호를 검증하는 기능만 제공하고, 비밀번호 자체는 클로저 외부에서 보지 못한다.

클로저 관련 예시 코드 (4)

  • 은행 계좌 관리 시스템
  • 클로저를 사용해 은행 계좌의 잔액을 관리한다. (외부에서 직접 잔액에 접근할 수 없도록 하고, depositwithdraw 메서드를 통해서만 잔액을 변경한다)
def bank_account(initial_balance):
    balance= initial_balance
    
    def deposit(amount):
        nonlocal balance
        if amount > 0:
            balance += amount
            return f"Deposited {amount}. New balance: {balance}"
        else:
            return "Deposit amount must be positive"
        
    def withdraw(amount):
        nonlocal balance
        if amount >0 and amount <= balance:
            balance -= amount
            return f"Withdrew {amount}. New balance: {balance}"
        elif amount > balance:
            return "Insufficient funds"
        else:
            return "Withdrawal amount must be positive"
        
    
    def get_balance():
        return f"Current balance: {balance}"
    
    return deposit, withdraw, get_balance

#은행 계좌 생성
deposit, withdraw, get_balance = bank_account(1000)

print(deposit(500))
print(withdraw(200))
print(get_balance())

# 잘못된 입금/출금
print(deposit(-100))
print(withdraw(2000))
  • bank_account 는 초기 잔액을 설정하고, 잔액 상태를 관리하는 클로저를 반환한다. 클로저는 deposit, withdraw, get_balance 메서드를 제공하며, 잔액은 외부에서 접근할 수 없다.
    nonlocal balance를 사용하여 내부 함수에서 balance값을 수정할 수 있다.

  • 상태 유지: 계좌의 잔액이 계속해서 업데이트되고, 클로저 외부에서는 잔액을 변경할 수 없다.

  • 데이터 은닉: balance는 외부에서 직접 접근할 수 없고, deposit, withdraw, get_balance를 통해서만 수정하거나 조회할 수 있다.

위 나오는 nonlocal에 대한 개념은 아래 링크 참고.
https://velog.io/@heyggun/python-nonlocal

결론

  • 클로저는 내부 함수가 외부 함수의 변수를 기억하고, 외부 함수가 종료된 후에도 그 값을 계속 참조하도록 하는 기능이다.
  • 클로저는 함수형 프로그래밍에서 중요한 역할을 하며, 상태를 유지하거나, 데이터 은닉을 구현할 때 유용하게 사용된다.
profile
꿈꾸는 것도 개발처럼 깊게

0개의 댓글