클래스 데코레이터
Coddy Python 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 64개 중 40번째.
class 데코레이터를 사용하면 다른 function으로 감싸 클래스를 수정하거나 향상할 수 있습니다. function 데코레이터와 같은 방식으로 작동하지만 전체 클래스에 적용됩니다.
다음은 데코레이션이 없는 간단한 클래스입니다:
class Person:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, my name is {self.name}"새로운 메서드를 추가하는 클래스 데코레이터를 만드세요:
def add_farewell(cls):
def farewell(self):
return f"Goodbye from {self.name}"
cls.farewell = farewell # 클래스에 메서드를 추가
return cls@를 사용하여 decorator를 class에 적용하세요:
@add_farewell
class EnhancedPerson:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, my name is {self.name}"이제 class에는 both original과 추가된 methods가 있습니다:
person = EnhancedPerson("Alice")
print(person.greet()) # 안녕하세요, 제 이름은 Alice입니다
print(person.farewell()) # Alice로부터 안녕히 가세요기존 method를 래핑할 수도 있습니다. original을 저장해 두면 wrapper 내부에서 여전히 호출할 수 있습니다. 이는 클래스가 이미 가지고 있는 method 주변에 behaviour(추적이나 로깅 등)를 추가하려는 경우 유용합니다:
def add_tracking(cls):
original_greet = cls.greet # 원본 메서드를 저장
def tracked_greet(self):
print(f"greet was called") # 호출 전 추가 동작
return original_greet(self) # 원본 메서드 호출
cls.greet = tracked_greet # 클래스의 메서드를 교체
return cls
@add_tracking
class TrackedPerson:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, my name is {self.name}"이제 greet을 호출하면 래퍼가 먼저 실행된 다음 원래 함수에 위임합니다.
person = TrackedPerson("Alice")
print(person.greet())
# greet가 호출되었습니다
# 안녕하세요, 제 이름은 Alice입니다기존 method를 래핑하는 주요 단계는 다음과 같습니다:
1. original method를 저장합니다: original = cls.method
2. original(self)을 호출하고 추가 로직을 포함하는 새로운 함수를 Define합니다.
3. 새로운 함수를 class에 다시 할당합니다: cls.method = new_function
4. modified class를 Return합니다.
핵심 요점: class decorator는 class를 input으로 받아 수정하거나 향상시키고, modified class를 반환합니다. methods를 추가하거나 속성을 수정하거나 기존 functionality를 래핑할 수 있습니다. class definition 위에 @decorator_name을 사용하여 적용합니다. 이를 통해 상속 없이도 class functionality를 확장하는 깔끔한 방법을 제공합니다.
챌린지
중급이 과제에서는 메서드 호출 추적 기능을 추가하는 클래스 데코레이터를 구현합니다.
decorator.py-add_counter클래스 데코레이터를 구현합니다calculator.py- 데코레이터를 사용할 클래스가 포함되어 있습니다
driver.py 파일에는 다양한 사용 사례, 상속 패턴 및 예외적인 경우에 대해 구현을 검증하는 광범위한 테스트 시나리오가 포함되어 있습니다. 이 파일을 수정할 필요는 없지만, 살펴보면 예상되는 동작을 이해하는 데 도움이 됩니다.
직접 해보기
from calculator import Calculator
# 포괄적인 테스트 케이스 핸들러
test_case = input()
if test_case == "basic_functionality":
calc = Calculator()
print(calc.add(5, 3)) # 8을 출력해야 함
print(calc.add(2, 7)) # 9를 출력해야 함
print(calc.subtract(10, 4)) # 6을 출력해야 함
print(calc.call_counts) # Should print {'add': 2, 'subtract': 1}
elif test_case == "multiple_instances":
calc1 = Calculator()
calc2 = Calculator()
print(calc1.add(5, 3)) # 8을 출력해야 함
print(calc2.add(2, 7)) # 9를 출력해야 함
print(calc1.subtract(10, 4)) # 6을 출력해야 함
# 두 인스턴스는 동일한 call_counts를 공유해야 함
print(calc1.call_counts) # Should print {'add': 2, 'subtract': 1}
print(calc2.call_counts) # Should print {'add': 2, 'subtract': 1}
print(calc1.call_counts is calc2.call_counts) # True를 출력해야 함
elif test_case == "method_call_order":
calc = Calculator()
print(calc.add(1, 2)) # 3을 출력해야 함
print(calc.subtract(5, 2)) # 3을 출력해야 함
print(calc.add(10, 20)) # 30을 출력해야 함
print(calc.add(7, 3)) # 10을 출력해야 함
print(calc.call_counts) # Should print {'add': 3, 'subtract': 1}
elif test_case == "large_values":
calc = Calculator()
print(calc.add(1000000, 2000000)) # 3000000을 출력해야 함
print(calc.subtract(5000000, 2000000)) # 3000000을 출력해야 함
print(calc.call_counts) # Should print {'add': 1, 'subtract': 1}
elif test_case == "negative_values":
calc = Calculator()
print(calc.add(-5, -3)) # -8을 출력해야 함
print(calc.subtract(-10, -4)) # -6을 출력해야 함
print(calc.call_counts) # Should print {'add': 1, 'subtract': 1}
elif test_case == "float_values":
calc = Calculator()
print(calc.add(5.5, 3.2)) # 8.7을 출력해야 함
print(calc.subtract(10.5, 4.2)) # 6.3을 출력해야 함
print(calc.call_counts) # Should print {'add': 1, 'subtract': 1}
elif test_case == "zero_values":
calc = Calculator()
print(calc.add(0, 0)) # 0을 출력해야 함
print(calc.subtract(0, 0)) # 0을 출력해야 함
print(calc.call_counts) # Should print {'add': 1, 'subtract': 1}
elif test_case == "counter_reset":
calc = Calculator()
print(calc.add(5, 3)) # 8을 출력해야 함
print(calc.call_counts) # Should print {'add': 1, 'subtract': 0}
# 카운터 재설정
calc.call_counts = {"add": 0, "subtract": 0}
print(calc.add(2, 7)) # 9를 출력해야 함
print(calc.call_counts) # Should print {'add': 0, 'subtract': 0}
elif test_case == "counter_manipulation":
calc = Calculator()
print(calc.add(5, 3)) # 8을 출력해야 함
print(calc.call_counts) # Should print {'add': 1, 'subtract': 0}
# 카운터를 직접 조작
calc.call_counts["add"] = 100
print(calc.add(2, 7)) # 9를 출력해야 함
print(calc.call_counts) # Should print {'add': 101, 'subtract': 0}
elif test_case == "performance_test":
calc = Calculator()
# 1000번의 add 연산 수행
for i in range(1000):
calc.add(i, i+1)
# 500번의 subtract 연산 수행
for i in range(500):
calc.subtract(i+10, i)
print(calc.call_counts) # Should print {'add': 1000, 'subtract': 500}이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 Python 컴파일러