
1. @decorator
데코레이터는 다른 함수를 감싸는 함수로, 기존 코드를 수정하지 않고도 동작을 추가하거나 변경할 수 있습니다.
파이썬에서는 @함수명 문법을 사용해 데코레이터를 적용합니다.
데코레이터는 함수뿐만 아니라 클래스에도 적용할 수 있습니다.
1. 1 @decorator 함수
데코레이터는 함수를 매개변수로 받아 내부에서 새로운 함수를 정의하고 반환합니다.
def my_decorator(func):
def wrapper():
print("Something before the function runs")
func() # 원래 함수 호출
print("Something after the function runs")
return wrapper
def say_hello():
print("Hello!")
아래 예시로 my_decorator, say_hello 두 함수가 있다고 치면 my_decorator함수에서 say_hello 함수가 호출되기 전에 중간에 메세지를 실행하고자 했을때
say_hello = my_decorator(say_hello)
say_hello()
이렇게 함수를 대입하여서 출력을 해주면 되는데, 문법이 조금 번거로운 감이 있습니다.
그럴때, 데코레이터를 사용하면 문법이 간결해지는데요,
[@데코레이터이름] 을 함수 위에 붙이면 데코레이터가 적용됩니다.
say_hello라는 함수 위에 @my_decorator 데코레이팅을 해주었으므로,
my_decorator 함수 인자에 say_hello 함수가 파라메터로 전달 되어 my_decorator(say_hello) 로 실행이 되겠네요.
@my_decorator
def say_hello():
print("Hello!")
say_hello()
그리고 호출할때는 say_hello()로 간단하게 호출이 가능해집니다.
정리하면 say_hello = my_decorator(say_hello) 이 문법을 간결하게 해주기 위해서 사용한다라고 생각하면 되겠네요.
출력 결과는 wapper 함수 내부에서 print 실행 구문 사이에 func() 함수가 정의되어 있으므로 아래와 같이 되겠습니다.
# 출력
Something before the function runs
Hello!
Something after the function runs
이 예제만으로는 사실 무슨 역할을 하는지 와닿지 않는데요, -_- 좀 더 실용적인 코드로 설명 해보겠습니다.
아래는 함수 실행 소요시간을 측정을 위해 정의한 함수입니다.
sample_function 함수에서 전달된 수치 범위 만큼 반복을 실행합니다. 해당 함수가 실행 되기 전에 start time, 반복문을 마친 후에 end time을 계산하는 목적입니다.
def timing_decorator(func):
def wrapper(*args, **kwargs):
# 함수 실행 전 시간 측정
start_time = time.time()
result = func(*args, **kwargs)
# 함수 실행 후 시간 측정
end_time = time.time()
# 함수 실행 시간 출력
print(
f"[알림] 함수명: <{func.__name__}> 실행에 {end_time - start_time:.6f} 초 소요되었습니다."
)
return result
return wrapper
@timing_decorator
def sample_function(n):
sum = 0
for i in range(n):
sum += i
return sum
# 함수 실행 및 시간 측정
sample_function(1000)
# 출력
[알림] 함수명: <sample_function> 실행에 0.0000XX 초 소요되었습니다.
499500
@timing_decorator로 정의해주어서 timing_decorator함수 인자에 sample_function이 전달 되게되고,
wapper함수에서 순차적으로 실행됩니다.
이렇게 다른 함수에서도 함수 실행 전에 시작,끝 시간을 측정 수행이 필요하다면 @timeing_decorator를 넣어주면 되겠죠?
이제 파이선 내장 기능의 데코레이터 메서드를 개념을 살펴보겠습니다.
2. built-in feature 데코레이터
2.2 @staticmethod
@staticmethod는 클래스에 소속된 메서드가 아니라 일반 함수를 정의하겠다는 의미로 생각하면 됩니다.
일반 메서드는 인스턴스 생성 후, 함수 호출 하지만
class MyClass:
def instance_method(self):
print(f"This is an instance method, self = {self}")
obj = MyClass()
obj.instance_method() # 인스턴스 생성 후 호출
@staticmethod는 인스턴스 없이 클래스.함수명으로 호출이 가능합니다.
class MyClass:
@staticmethod
def static_method():
print("This is a static method, no instance required")
MyClass.static_method() # 인스턴스 없이 호출
클래스 상태와 무관한 경우, 정적 메서드(@staticmethod)를 사용합니다.
2.2.1 클래스 상태
클래스 상태란 클래스 변수와 인스턴스 속성을 통해 접근하거나 수정할 수 있는 데이터를 의미합니다.
클래스 변수는 클래스 정의에서 메서드 밖에 존재하는 변수입니다. 해당 클래스를 사용하는 공용 변수입니다.
'클래스명.변수명'으로 액세스 할 수 있습니다.
아래 예제의 경우 class_variable가 공용 변수로 MyClass.class_variable로 접근 할 수 있겠습니다.
class MyClass:
class_variable = "I belong to the class" # 클래스 변수
def __init__(self):
self.instance_variable = "I belong to an instance" # 인스턴스 변수
# 클래스 상태 접근
print(MyClass.class_variable) # "I belong to the class"
obj = MyClass()
print(obj.instance_variable) # "I belong to an instance"
인스턴스 변수는 각 객체별로 서로 다른 값을 갖는 변수입니다.
클래스 내부에서 인스턴스 변수에 접근하려면 self 키워드를 사용하여 "self.변수명"으로 접근합니다.
class Rectangle:
def __init__(self, width, height):
self.width = width # 인스턴스 변수
self.height = height # 인스턴스 변수
def area(self):
return self.width * self.height # self를 통해 접근
클래스 외부에서는 객체.인스턴스변수를 사용하여 접근합니다.
rect = Rectangle(10, 5) # Rectangle 클래스의 인스턴스 생성
print(rect.width) # 객체명.rect.width로 접근
print(rect.height) # 객체명.rect.height로 접근
2.3 @classmethod
@classmethod는 클래스 자체를 매개변수로 전달 받습니다. 관례적으로 cls 키워드를 사용합니다. cls는 호출된 클래스 자체를 뜻합니다.
class Korean:
country = "korea" # 클래스 변수
# 일반 메서드
def i_change(self, name):
self.country = name # 인스턴스 변수로 접근
# 클래스 메서드
@classmethod
def c_change(cls, name):
cls.country = name # 클래스 변수로 접근
i_change 메서드는 self.country 인스턴스 변수로 작동하여 특정 인스턴스 변수만 변경합니다. 클래스 변수 country와는 독립적입니다.
# 인스턴스 생성
person1 = Korean()
person2 = Korean()
# 인스턴스 메서드 호출
person1.i_change("US")
# 확인
print(person1.country) # "US" (person1의 인스턴스 변수만 변경됨)
print(person2.country) # "korea" (person2의 인스턴스 변수는 변경되지 않음)
print(Korean.country) # "korea" (클래스 변수는 변경되지 않음)
c_change 메서드는 cls.country를 통해 클래스 변수에 직접 접근하여 변경합니다.
# 클래스 메서드 호출
Korean.c_change("china")
# 확인
print(Korean.country) # "china" (클래스 변수 변경됨)
person1 = Korean()
person2 = Korean()
print(person1.country) # "china" (모든 인스턴스에 영향)
print(person2.country) # "china"
정리하면 일반 메서드는 특정 인스턴스 변수를 변경하고 클래스 변수는 영향 받지 않습니다.
@classmethod는 클래스 변수를 변경하고 모든 인스턴스에서 해당 변경 값을 참조합니다.
@staticmethod는 클래스나 인스턴스에 의존하지 않는 메서드입니다.
'Programming👩🏻💻 > Python' 카테고리의 다른 글
[Python] - Caching 캐싱 적용하기 (1) | 2024.12.10 |
---|---|
[pandas 🐼] - 기본 데이터 구조 (0) | 2024.12.02 |
Statements vs Expressions 차이 (0) | 2024.11.11 |
파이썬 모듈, 패키지 (0) | 2024.11.10 |
시퀀스 연산 (0) | 2024.11.05 |