Python 네임스페이스 스코프와 함수 객체 활용

스코프는 네임스페이스가 효력을 발휘하는 범위를 의미합니다. 파이썬에는 내장 네임스페이스, 전역 네임스페이스, 지역 네임스페이스가 존재합니다.

  • 내장 네임스페이스: 프로그램의 어떤 시점, 어떤 위치에서든 접근 가능합니다.
  • 전역 네임스페이스: 프로그램 전체에서 접근 가능합니다.
  • 지역 네임스페이스: 일반적으로 해당 지역(함수 내부 등)에서만 유효합니다.

globalnonlocal 키워드

global 키워드는 지역 네임스페이스에서 전역 네임스페이스의 변수를 수정할 때 사용합니다. 특히 변경 불가능한(immutable) 타입의 변수를 다룰 때 필요합니다.

nonlocal 키워드는 지역 네임스페이스에서 지역 외부 네임스페이스의 변수를 수정할 때 사용합니다. 이 역시 변경 불가능한 타입의 변수에 적용됩니다.

함수 객체 (함수명)

함수명 뒤에 괄호()가 붙으면 함수가 호출됩니다. 이를 기억하는 것이 중요합니다.

  1. 함수명을 변수에 할당: 함수명을 변수에 할당하는 것은 함수를 호출하고 함수 본문 코드를 실행하는 것과 동일합니다.
    
    def greet():
        print("Hello from greet")
    
    my_func_ref = greet
    print(my_func_ref())
    # 출력:
    # Hello from greet
    # None
            
  2. 함수명을 함수의 인자로 전달: 함수명을 다른 함수의 인자로 전달하면, 해당 함수 본문 내에서 전달된 함수를 실행할 수 있습니다.
    
    def greet():
        print("Executing greet")
    
    def execute_callback(callback_func):
        print("Inside execute_callback")
        callback_func()
        print("Finished execute_callback")
    
    execute_callback(greet)
    # 출력:
    # Inside execute_callback
    # Executing greet
    # Finished execute_callback
            
  3. 함수명을 함수의 반환 값으로 사용: 함수는 다른 함수의 반환 값으로 사용될 수 있습니다.
    
    def get_greeter():
        print("Creating greeter function")
        def greeter():
            print("Hello!")
        return greeter
    
    create_func = get_greeter()
    create_func()
    # 출력:
    # Creating greeter function
    # Hello!
            
  4. 함수명을 컨테이너(리스트, 딕셔너리 등)의 요소로 사용: 함수는 리스트나 딕셔너리와 같은 컨테이너의 요소로 저장될 수 있습니다.
    
    def perform_action():
        print("Action performed")
    
    actions = [1, 2, perform_action]
    print(actions)
    actions[2]() # 리스트의 세 번째 요소(함수)를 호출
    # 출력:
    # [1, 2, <function perform_action at ...>]
    # Action performed
            

예제: 메뉴 기반 기능 실행

다양한 기능을 함수로 정의하고, 사용자의 입력에 따라 해당 함수를 실행하는 예제입니다.


def register_user():
    print('User Registration')

def user_login():
    print('User Login')

def shop_items():
    print('Shopping')

def transfer_funds():
    print('Fund Transfer')

def withdraw_cash():
    print('Cash Withdrawal')

def view_order():
    print('View Orders')

operations = {
    '1': (register_user, "User Registration"),
    '2': (user_login, "User Login"),
    '3': (shop_items, "Shopping"),
    '4': (transfer_funds, "Fund Transfer"),
    '5': (withdraw_cash, "Cash Withdrawal"),
    '6': (view_order, "View Orders")
}

while True:
    print("\n--- Menu ---")
    for key, (func, description) in operations.items():
        print(f"{key}: {description}")
    print("0: Exit")

    choice = input("Enter your choice (0-6): ").strip()

    if choice == '0':
        print("Goodbye!")
        break
    elif choice in operations:
        selected_function, _ = operations[choice]
        selected_function()
    else:
        print("Invalid choice. Please enter a valid number.")

함수의 중첩 사용 (호출)

함수 내에서 다른 함수를 호출하는 것을 의미합니다. 복잡한 기능을 작은 단위로 분리하여 재사용성을 높일 수 있습니다.


def find_maximum(a, b):
    if a > b:
        return a
    return b

def find_overall_maximum(num1, num2, num3, num4):
    max_val1 = find_maximum(num1, num2)
    max_val2 = find_maximum(max_val1, num3)
    final_max = find_maximum(max_val2, num4)
    return final_max

result = find_overall_maximum(10, 25, 15, 30)
print(f"The overall maximum is: {result}")
# 출력:
# The overall maximum is: 30

함수의 중첩 정의

함수 본문 내에 다른 함수를 정의하는 것입니다. 이는 복잡한 로직을 캡슐화하고 외부에는 단순한 인터페이스만 노출할 때 유용합니다.


def handle_request(request_type):
    def process_registration():
        print('Processing registration...')

    def process_login():
        print('Processing login...')

    def process_transfer():
        print('Processing fund transfer...')

    if request_type == 'register':
        process_registration()
    elif request_type == 'login':
        process_login()
    elif request_type == 'transfer':
        process_transfer()
    else:
        print("Unknown request type")

handle_request('login')
# 출력:
# Processing login...

클로저 함수

클로저는 다음과 같은 두 가지 조건을 만족하는 함수입니다.

  1. 내부 함수: 함수 내부에 정의된 함수입니다.
  2. 이름 참조: 내부 함수가 외부 함수의 네임스페이스에 있는 이름을 참조합니다.

클로저는 인자를 전달하는 또 다른 방법으로 볼 수 있습니다.


def configure_comparison(val1, val2):
    # val1과 val2는 외부 함수의 인자이며, 내부 함수에서 사용됩니다.
    def compare_values():
        if val1 > val2:
            return val1
        return val2
    return compare_values # 내부 함수 자체를 반환

# val1=5, val2=10으로 설정된 compare_values 함수 생성
comparison_instance1 = configure_comparison(5, 10)
print(comparison_instance1()) # 10 출력

# val1=20, val2=15으로 설정된 compare_values 함수 생성
comparison_instance2 = configure_comparison(20, 15)
print(comparison_instance2()) # 20 출력

클로저 활용 예시 (웹 요청)

requests 라이브러리를 사용하여 웹 페이지 내용을 가져오는 클로저 예제입니다.


import requests
import os

def create_web_fetcher(url):
    def fetch_and_save():
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status() # HTTP 오류 발생 시 예외 발생
            
            # 파일명 생성 (URL 기반)
            filename = url.split('//')[-1].replace('/', '_').replace('.', '_') + ".html"
            filepath = os.path.join(os.getcwd(), filename)

            with open(filepath, 'wb') as f:
                f.write(response.content)
            print(f"Content from {url} saved to {filepath}")
        except requests.exceptions.RequestException as e:
            print(f"Error fetching {url}: {e}")
        except IOError as e:
            print(f"Error saving file for {url}: {e}")
            
    return fetch_and_save

# baidu.com의 콘텐츠를 가져오는 함수 생성
baidu_fetcher = create_web_fetcher('https://www.baidu.com')
baidu_fetcher()

# jd.com의 콘텐츠를 가져오는 함수 생성
jd_fetcher = create_web_fetcher('https://www.jd.com')
jd_fetcher()

데코레이터

데코레이터는 네임스페이스, 함수 객체, 클로저 함수의 조합으로 이루어집니다. '기구'처럼 기존 객체에 '장식'하여 추가 기능을 부여하는 역할을 합니다.

데코레이터의 원칙 (개방-폐쇄 원칙):

  • 개방 (Open): 확장에 열려 있어야 합니다.
  • 폐쇄 (Closed): 수정에는 닫혀 있어야 합니다.

데코레이터의 핵심 아이디어:

원본 함수의 내부 코드나 기존 호출 방식을 변경하지 않으면서 새로운 기능을 추가하는 것입니다.

실행 시간 측정 데코레이터 예제

함수의 실행 시간을 측정하는 간단한 데코레이터를 구현합니다.


import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function '{func.__name__}' executed in {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timing_decorator
def slow_operation(duration):
    print(f"Performing operation for {duration} seconds...")
    time.sleep(duration)
    print("Operation complete.")
    return "Operation Result"

# 데코레이터가 적용된 함수 호출
operation_result = slow_operation(2)
print(f"Result: {operation_result}")

# 출력 예시:
# Performing operation for 2 seconds...
# Operation complete.
# Function 'slow_operation' executed in 2.00XX seconds
# Result: Operation Result

태그: python 네임스페이스 스코프 함수 객체 클로저

6월 8일 22:43에 게시됨