스코프는 네임스페이스가 효력을 발휘하는 범위를 의미합니다. 파이썬에는 내장 네임스페이스, 전역 네임스페이스, 지역 네임스페이스가 존재합니다.
- 내장 네임스페이스: 프로그램의 어떤 시점, 어떤 위치에서든 접근 가능합니다.
- 전역 네임스페이스: 프로그램 전체에서 접근 가능합니다.
- 지역 네임스페이스: 일반적으로 해당 지역(함수 내부 등)에서만 유효합니다.
global 및 nonlocal 키워드
global 키워드는 지역 네임스페이스에서 전역 네임스페이스의 변수를 수정할 때 사용합니다. 특히 변경 불가능한(immutable) 타입의 변수를 다룰 때 필요합니다.
nonlocal 키워드는 지역 네임스페이스에서 지역 외부 네임스페이스의 변수를 수정할 때 사용합니다. 이 역시 변경 불가능한 타입의 변수에 적용됩니다.
함수 객체 (함수명)
함수명 뒤에 괄호()가 붙으면 함수가 호출됩니다. 이를 기억하는 것이 중요합니다.
- 함수명을 변수에 할당: 함수명을 변수에 할당하는 것은 함수를 호출하고 함수 본문 코드를 실행하는 것과 동일합니다.
def greet(): print("Hello from greet") my_func_ref = greet print(my_func_ref()) # 출력: # Hello from greet # None - 함수명을 함수의 인자로 전달: 함수명을 다른 함수의 인자로 전달하면, 해당 함수 본문 내에서 전달된 함수를 실행할 수 있습니다.
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 - 함수명을 함수의 반환 값으로 사용: 함수는 다른 함수의 반환 값으로 사용될 수 있습니다.
def get_greeter(): print("Creating greeter function") def greeter(): print("Hello!") return greeter create_func = get_greeter() create_func() # 출력: # Creating greeter function # Hello! - 함수명을 컨테이너(리스트, 딕셔너리 등)의 요소로 사용: 함수는 리스트나 딕셔너리와 같은 컨테이너의 요소로 저장될 수 있습니다.
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...
클로저 함수
클로저는 다음과 같은 두 가지 조건을 만족하는 함수입니다.
- 내부 함수: 함수 내부에 정의된 함수입니다.
- 이름 참조: 내부 함수가 외부 함수의 네임스페이스에 있는 이름을 참조합니다.
클로저는 인자를 전달하는 또 다른 방법으로 볼 수 있습니다.
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