파이썬은 데코레이터(decorator)라는 기능을 제공한다. 데코레이터는 장식하다, 꾸미다라는 뜻의 decorate에 er(or)을 붙인 말인데 장식하는 도구 정도로 설명할 수 있다.
파이썬에서 데코레이터는 함수를 받아 명령을 추가한 뒤 이를 다시 함수의 형태로 반환하는 함수이다.
함수의 내부를 수정하지 않고 기능에 변화를 주고 싶을 때 사용한다.
데코레이터를 이용해, 반복을 줄이고 메소드나 함수의 책임을 확장한다.
자바, 파이썬 객체지향형 언어의 클래스에서 메서드를 만들 때 @staticmethod, @classmethod, @abstractmethod 등을 붙였는데, 이렇게 @로 시작하는 것들이 데코레이터이다.
@데코레이터 사용하기
데코레이터 사용을 위한 예제코드
def Hello():
print('-' * 15)
print('hello 출력시작')
print('hello')
print('hello 출력끝')
print('-' * 15)
def Python():
print('-' * 15)
print('python 출력시작')
print('python')
print('python 출력끝')
print('-' * 15)
Hello()
Python()
실행결과
-----------
hello 출력시작
hello
hello 출력끝
-----------
-----------
python 출력시작
python
python 출력끝
-----------
위 내용처럼 print를 코드실행상 상관없지만 함수가 많아지고 코드가 복잡해지면 매우 번거로운 작업이 될 것이다.
그래서 다음과 같이 호출할 함수 위에 @데코레이터 형식으로 지정하는 방법을 추천한다.
def decorator_test(func): # 호출할 함수를 매개변수로 받음
def print_test():
print('-' * 15)
print(func.__name__, '출력시작') # __name__으로 함수 이름 출력
func() # 매개변수로 받은 함수를 호출
print(func.__name__, '출력끝')
print('-' * 15)
return print_test # print_test 함수 반환
@decorator_test # @데코레이터
def hello():
print('hello')
@decorator_test # @데코레이터
def Python():
print('Python')
hello() # 함수를 그대로 호출
Python() # 함수를 그대로 호출
실행결과
-----------
hello 출력시작
hello
hello 출력끝
-----------
-----------
python 출력시작
python
python 출력끝
-----------
지금은 코드길이가 많이 줄지 않았지만 프로젝트 진행하면서 데코레이터를 잘 사용하면 코드 가독성과 깔끔한 코드를 작성하는데 큰 도움이 될 것이다.
자주쓰는 데코레이터 알아보기
- @property
- @abstractmethod
- @staticmethod
- @calssmethod
1. @app.route
route() 메소드는 파이썬 Flask에서 제공하는 데코레이터이다.
route는 외부 웹브라우져에서 웹서버로 접근 시 해당 주소로 입력을 하게 되면 특정 함수가 실행되게 도와주는 기능을 한다.
<예시>
from flask import *
app = Flask(__name__, template_folder="templates")
@app.route('/hello')
def hello():
return 'hello, world'
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True, port=9999)
---실행---
실행결과
2. @property
property 메서드는 python에 내장되어있는 함수이다.
property()를 사용하면 마치 필드명을 사용하는 것처럼 깔끔하게 getter/setter 메서드가 호출되게 할 수 있다.
class Person :
def __init__(self):
self.__name = 'kwon'
def get_name(self):
return self.__name
def set_name(self, name):
self.__name = name
위와 같이 하나만 있을때는 크게 상관없지만 많은 get, set 메소드를 만들면 함수가 너무 많아지고 복잡해진다.
위 내용을 @property를 통해 좀 더 직관적이고 간단하게 표현할 수 있다.
class Person :
def __init__(self):
self.__name = 'kwon'
@property
def name(self):
return self.__name
@name.setter
def name(self, name):
self.__name = name
person = Person()
print(person.name) # kwon
person.name = 'zeus'
print(person.name) # zeus
get 역할은 @property
set 역할은 @name.setter가 한다.
주의할 점은 @property가 setter보다 윗줄에 사용되어야 한다.
3. @abstractmethod
@abstractmethod는 인터페이스나 추상클래스에 있는 추상메소드이다.
- 추상클래스 : 단어 뜻 그대로 완성되지 못한 채로 남겨진 미완성 설계도로 비유할 수 있다.
- 추상 메서드 : 메서드는 선언부와 구현부로 구성되어있는데 추상메서드는 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 메서드를 뜻한다.
추상클래스를 사용하는 이유로는 자손 클래스에서 추상메서드를 반드시 구현하도록 강요하기 위해서이다.
상속받는 자손클래스에서는 메서드들이 완전히 구현된 것으로 인식하고 오버라이딩을 하지 않을 수 있기 때문이다.
- 문법
Drow 메소드에 abstractmethod 데코레이터를 적용하여 추상 메소드로 정의한다.
from abc import ABC, abstractmethod
class Shape(ABC) :
@abstractmethod
def Draw(self) :
pass
class Rect(Shape) :
pass
s = Shape() # TypeError: Can't instantiate abstract class Shape with abstract method Draw
r = Rect()
r.Draw()
조상클래스에서 Draw()메서드를 추상메서드로 정의하고 자손클래스 Rect()에서 추상메소드가 구현이 안되어있으면 에러가 발생한다.
from abc import ABC, abstractmethod
class Shape(ABC) :
@abstractmethod
def Draw(self) :
pass
class Rect(Shape) :
def Draw(self) :
print('Draw Rect')
r = Rect()
r.Draw() # Draw Rect
자손클래스는 추상메서드로 선언된 부분에 대해서 선언해줘야 하는 강제성이 부여 됨
4. @staticmethod & @classmethod 정적메소드
@staticmethod와 @classmethod는 정적메소드로 분류가 된다.
- 정적메소드는 클래스에서 직접 접근할 수 있는 메소드이다.
- 파이썬에서는 정적메소드임에도 불구하고 인스턴스에서도 접근이 가능하다.
- 둘 다 인스턴스를 만들지 않아도 class의 메서드를 바로 실행 할 수 있다.
(예시)
- @staticmethod
class Calc:
@staticmethod
def add(a ,b):
return a + b
cal = Calc()
cal.add(1,2) # return 3
- @classmethod
class Calc:
@classmethod
def add(cls, a ,b):
return a + b
cal = Calc()
cal.add(1,2) # return 3
두 클래스의 차이점으로 @classmethod에서 cls라는 인자를 추가로 가진다.
두 정적 메소드의 차이는 상속을 받을 때 차이가 난다.
@Classmethod와 @staticmethod의 차이
class Person:
default= "조상"
def __init__(self):
self.data = self.default
@classmethod
def class_person(cls):
return cls()
@staticmethod
def static_person():
return Person()
class WhatPerson(Person):
default = "손자"
person1 = WhatPerson.class_person() # return 손자
person2 = WhatPerson.static_person() # return 조상
@staticmethod의 경우 부모 클래스의 클래스 속성 값을 가져오지만 @classmethod의 경우 cls인자를 활용하여 현재 클래스의 클래스 속성을 가져온다.
'Python' 카테고리의 다른 글
[colab] 코랩에서 pandas로 데이터 불러오기(csv,json) (0) | 2022.02.20 |
---|---|
pandas기초 _ 데이터 전처리(합치기(concat, merge), Groupby) (0) | 2021.05.19 |
pandas기초 _ Feature Engineering(String replace, Apply 사용법) (0) | 2021.05.18 |
pandas기초 _ 데이터 전처리(EDA란, Data Preprocessing) (0) | 2021.05.15 |