파이썬 - 래퍼 클래스

래퍼 클래스 소개

안녕하세요, 미래의 파이썬 마법사 여러분! 오늘, 우리는 래퍼 클래스의 세계로 흥미로운 여정을 떠날 거예요. 프로그래밍에 새로운 사람이라도 걱정하지 마세요 – 저는 여러분을 단계별로 이 개념을 안내해 드리겠습니다. 마치 저가 수년간 가르쳐 온 수많은 학생들을 안내한 것처럼요.

Python - Wrapper Classes

아름다운 선물을 가지고 있다고 생각해 보세요. 그러나 그 선물을 더 특별하게 만들기 위해 예쁜包装纸에 싸는 것 같아요. 이것은 파이썬에서 래퍼 클래스를 사용하는 것과 정확히 같아요 – 기존의 객체를 가져와 추가 기능을 "싸는" 것이에요. 멋지죠?

래퍼 클래스란?

래퍼 클래스는 다른 클래스의 객체나 기본 데이터형을 (또는 "싸는") 클래스입니다. 이는 스마트폰에 보호 케이스를 끼는 것과 같아요 – 폰은 여전히 같은 방식으로 작동하지만, 이제 추가 기능과 보호를 가지게 됩니다.

래퍼 클래스를 왜 사용하나요?

  1. 기존 객체에 새로운 기능을 추가하기 위해
  2. 기존 메서드의 행동을 수정하기 위해
  3. 원본 객체에 대한 접근을 제어하기 위해

이제 실제 코드 예제를 통해 이是如何 작동하는지 살펴보겠습니다!

기본 래퍼 클래스 예제

class StringWrapper:
def __init__(self, string):
self.string = string

def get_string(self):
return self.string

def append(self, text):
self.string += text

# 래퍼 사용
wrapped_string = StringWrapper("Hello")
print(wrapped_string.get_string())  # 출력: Hello
wrapped_string.append(" World!")
print(wrapped_string.get_string())  # 출력: Hello World!

이 예제에서, 우리는 문자열을 위한 간단한 래퍼 클래스를 정의했습니다. 이를 분석해 보죠:

  1. StringWrapper라는 클래스를 정의합니다.
  2. __init__ 메서드는 래퍼를 문자열로 초기화합니다.
  3. get_string()는包装된 문자열을检索할 수 있게 합니다.
  4. append()는 새로운 메서드로 기능을 추가합니다 – 문자열에 텍스트를 추가합니다.

기본 문자열에 새로운 기능(추가)를 추가했는지 볼 수 있죠? 이것이 래퍼 클래스의 힘입니다!

래퍼 클래스로 행동 수정

이제 기존 메서드의 행동을 어떻게 수정할 수 있는지 살펴보겠습니다:

class ShoutingList(list):
def __getitem__(self, index):
return super().__getitem__(index).upper()

# 래퍼 사용
normal_list = ["hello", "world", "python"]
shouting_list = ShoutingList(normal_list)

print(normal_list[0])     # 출력: hello
print(shouting_list[0])   # 출력: HELLO

이 예제에서:

  1. 빌트인 list 클래스에서 상속받은 ShoutingList 클래스를 만듭니다.
  2. __getitem__ 메서드를 오버라이드하여 대문자 문자열을 반환합니다.
  3. ShoutingList에서 항목에 접근할 때, 자동으로 대문자로 변환됩니다.

이는 친구가 당신이 말한 것을 반복할 때 항상 외치는 것과 같아요 – 같은 내용, 다른 전달 방식!

래퍼 클래스로 접근 제어

래퍼 클래스는 원본 객체에 대한 접근을 제어하는 데도 사용할 수 있습니다. 이는 데이터 보호 또는 읽기 전용 객체를 구현하는 데 특히 유용합니다:

class ReadOnlyWrapper:
def __init__(self, data):
self._data = data

def get_data(self):
return self._data

def __setattr__(self, name, value):
if name == '_data':
super().__setattr__(name, value)
else:
raise AttributeError("이 객체는 읽기 전용입니다")

# 래퍼 사용
data = [1, 2, 3]
read_only_data = ReadOnlyWrapper(data)

print(read_only_data.get_data())  # 출력: [1, 2, 3]
read_only_data.get_data().append(4)  # 이 작동합니다, 원본 목록을 수정합니다
print(read_only_data.get_data())  # 출력: [1, 2, 3, 4]

try:
read_only_data.new_attribute = "이거 추가 못해요"
except AttributeError as e:
print(e)  # 출력: 이 객체는 읽기 전용입니다

이 예제에서:

  1. 읽기 전용으로 동작하는 ReadOnlyWrapper 클래스를 정의합니다.
  2. __setattr__를 오버라이드하여 래퍼에 새로운 속성을 추가하지 못하게 합니다.
  3. 원본 데이터는 여전히 get_data()를 통해 수정될 수 있지만, 래퍼 자체에 새로운 속성을 추가할 수 없습니다.

이는 박물관 전시와 같아요 – 볼 수는 있지만, 만지는 수는 없어요!

래퍼 클래스의 실제 응용

래퍼 클래스는 많은 실제 세계 응용이 있습니다. 몇 가지 예를 들어보겠습니다:

  1. 로깅: 메서드 호출이나 속성 접근을 로그하기 위해 객체를包装합니다.
  2. 캐싱: 비용이高的인 작업에 대한 캐싱 계층을 구현합니다.
  3. 입력 검증: 데이터가 특정 기준을 충족하기 전까지 사용하지 않도록 추가 검사합니다.
  4. 지연 로딩: 실제로 필요할 때까지 객체 생성을 연기합니다.

이제 간단한 로깅 래퍼를 구현해 보겠습니다:

import time

class LoggingWrapper:
def __init__(self, obj):
self.wrapped_obj = obj

def __getattr__(self, name):
original_attr = getattr(self.wrapped_obj, name)
if callable(original_attr):
def wrapper(*args, **kwargs):
start_time = time.time()
result = original_attr(*args, **kwargs)
end_time = time.time()
print(f"{name} 호출, {end_time - start_time:.2f} 초 걸림")
return result
return wrapper
return original_attr

# 래퍼 사용
class SlowCalculator:
def add(self, x, y):
time.sleep(1)  # 느린 작업 시뮬레이션
return x + y

calc = SlowCalculator()
logged_calc = LoggingWrapper(calc)

result = logged_calc.add(3, 4)
print(f"결과: {result}")

출력:

add 호출, 1.00 초 걸림
결과: 7

이 예제에서:

  1. 모든 객체를包装할 수 있는 LoggingWrapper를 정의합니다.
  2. 메서드 호출을 가로채고, 시간을 기록한 후, 원래 메서드를 호출합니다.
  3. SlowCalculator 객체를包装하고 메서드 호출을 로깅합니다.

이는 모든 작업을 시간을 잰 후 보고해주는 개인 비서와 같아요!

결론

래퍼 클래스는 파이썬에서 객체를 확장하고, 수정하고, 유연하게 제어할 수 있는 강력한 도구입니다. 이는 오브젝트-орientoed 프로그래밍의 스위스 Army 톱니칼과 같아요 – 다양하고 매우 유용한 상황에서 사용할 수 있습니다.

기억해 주세요, 래퍼 클래스를 마스터하기의 열쇠는 연습입니다. 다양한 객체에 대해 자신의 래퍼를 만들어 보고, 기능을 어떻게 확장할 수 있는지 확인해 보세요.谁知道? 여러분이 파이썬 마스터로서의 길을 래핑하는 방식으로 가볼 수 있을지도 모릅니다!

코딩을 즐겁게, 여러분의 코드가 항상 깔끔하게包装되길 바랍니다! ??



| 메서드 | 설명 |
|--------|-------------|
| `__init__(self, obj)` | 래퍼를包装할 객체로 초기화 |
| `__getattr__(self, name)` | 래퍼에서 속성 접근을 가로채 |
| `__setattr__(self, name, value)` | 래퍼에서 속성 대입을 가로채 |
| `__getitem__(self, key)` | 항목 접근 (예: 목록류 객체)를 가로채 |
| `__setitem__(self, key, value)` | 항목 대입을 가로채 |
| `__call__(self, *args, **kwargs)` | 包装된 객체가 호출 가능하면 래퍼를 호출 가능하게 |
| `__iter__(self)` | 包装된 객체가 이터러블이면 래퍼를 이터러블하게 |
| `__len__(self)` | 래퍼의 길이를 보고 |
| `__str__(self)` | 래퍼의 문자열 표현을 사용자 정의 |
| `__repr__(self)` | 래퍼의 repr 표현을 사용자 정의 |

이 메서드들은 여러분의 래퍼 클래스가 코드의 나머지 부분과 상호작용할 때의 거의 모든 측면을 사용자 정의할 수 있게 합니다.包装된 객체의 상호작용을 세밀하게 제어할 수 있습니다.

Credits: Image by storyset