안녕하세요, 온라인 코딩 스쿨 코드잇입니다.
오늘은 파이썬에서 사용하는 데코레이터(decorator)를 알아보겠습니다.
데코레이터(decorator)라는 건 함수나 메소드의 이름 위에 쓰는, 맨 앞에 골뱅이가 붙은 표시를 말합니다.
데코레이터가 뭔지 바로 코드를 갖고 설명해드릴게요~!
def quick_fix(func): # (1) def result(car_speed, speed_standard): # (2) if func(car_speed, speed_standard): # (3) print('적발! 제한 속도 {}km/h 초과'.format(car_speed-speed_standard)) # (4) return True # (5) else: return False # (6) return result # (7) @quick_fix def is_speeding(speed, standard): return speed > standard
위 코드가 고속도로 위의 과속 차량 단속 기계에 쓰인다고 가정하겠습니다. 코드에 있는 is_speeding 함수는 측정된 차량의 속도와 제한 속도를 비교해서 과속 차량인지 아닌지를 판단합니다. 그래서 과속 차량이면 True를, 과속 차량이 아니면 False를 리턴하는데요.
그런데 갑자기 정부 정책이 과속 차량인 경우에는 제한 속도보다 얼마만큼 더 과속을 했는지까지도 기록해야하는 것으로 바뀌면 어떻게 해야할까요? 위 코드는 데코레이터로 그 문제를 해결한 건데요.
위 코드에서 데코레이터는 @quick_fix 이 부분입니다. 데코레이터는 어떤 함수를 꾸며서 새 함수로 만들어주는 기능을 합니다. 데코레이터에서 골뱅이 뒤에 있는 단어는 어떤 함수의 이름인데요. 그 함수가 어떤 함수를 꾸며주는 함수입니다. 지금 골뱅이 뒤에 quick_fix라고 써있죠?
자세히 보면 is_speeding 함수 위에 있는 함수의 이름이 quick_fix 입니다. 그러니까 지금 quick_fix 함수가 is_speeding 함수를 꾸며주고 있는 겁니다.
어떤 원리로 꾸며주고 있는 걸까요? 이 부분이 핵심입니다. 집중하세요! 지금 위 코드 중에서 이 부분은
@quick_fix def is_speeding(speed, standard): return speed > standard
아래 코드와 같은 뜻입니다.
is_speeding = quick_fix(is_speeding)
그러니까 is_speeding 함수가 이름은 그대로지만 quick_fix라는 함수에 의해 새로운 함수가 된 겁니다. 다른 말로 하면, quick_fix 라는 함수가 is_speeding 함수를 꾸며서 새로운 함수로 만든 건데요. quick_fix 함수가 내부에서 어떤 동작을 하는 걸까요?
quick_fix 함수의 내부를 살펴보겠습니다. 각 줄의 맨 오른쪽에 붙인 주석 번호대로 하나씩 설명해드리겠습니다.
def quick_fix(func): # (1) def result(car_speed, speed_standard): # (2) if func(car_speed, speed_standard): # (3) print('적발! 제한 속도 {}km/h 초과'.format(car_speed-speed_standard)) # (4) return True # (5) else: return False # (6) return result # (7)
(1) quick_fix 함수는 어떤 함수를 (여기서는 is_speeding 함수) func 이라는 파라미터로 받습니다.
(2) 그리고 result 라는 새로운 함수를 정의하는데요. result 함수는 지금 is_speeding과 같은 수의 인자를 갖고 있네요? 단어 뜻을 비교해봐도 speed와 car_speed, standard 와 speed_standard, 뭔가 생김새가 비슷하네요. 이 result 함수가 새로운 is_speeding 함수가 되기 때문에 그런 겁니다. result 함수의 내용을 살펴보면,
(3) 파라미터로 받은 car_speed 와 speed_standard 를 func 함수에 그대로 넘겨 과속 여부를 판단합니다.
(4) 과속인 경우에는 차량 속도에서 기준 속도를 빼서 해당 차량이 얼마만큼 과속을 했는지를 출력합니다. 바로 이 부분이 정부 정책 변경으로 인해 추가된 기능입니다.
(5) 그리고 True를 리턴하네요.
(6) 과속이 아닐 때는 False를 리턴하구요.
(7) 이 부분이 중요한데요. is_speeding 함수에 약간의 기능을 더 추가한 result 함수를 리턴해줍니다.
이 내용을 정리하면 결국 아래 코드는 is_speeding 함수가 quick_fix 함수 내에서 새로 정의한 result 함수가 된 것임을 나타냅니다. 그러니까 @quick_fix 데코레이터가 적용된 is_speeding 함수는 result 함수인 겁니다.
is_speeding = quick_fix(is_speeding)
그럼 정말 데코레이터를 통해 is_speeding 함수가 기능이 추가된 새 함수가 되었는지 볼까요?
맨 아래와 같은 코드 2줄을 추가하고 다시 실행해보면
def quick_fix(func): # (1) def result(car_speed, speed_standard): # (2) if func(car_speed, speed_standard): # (3) print('적발! 제한 속도 {}km/h 초과'.format(car_speed-speed_standard)) # (4) return True # (5) else: return False # (6) return result # (7) @quick_fix def is_speeding(speed, standard): return speed > standard print(is_speeding(150, 110)) print(is_speeding(100, 110))
이런 결과가 출력됩니다.
적발! 제한 속도 40km/h 초과 True False
차량이 과속을 했을 땐 기준 속도(110km/h)보다 얼마만큼(40km/h) 과속을 했는지가 잘 출력되네요. 과속을 안 했을 땐 그냥 False만 출력하구요. 정부 정책의 변경에 맞게 잘 수정되었죠?
이때까지의 내용이 잘 이해되셨나요? 여러분 중에는 quick_fix 함수 안에 result라는 함수를 정의하는 게 어색하게 느껴지는 분이 계실 수도 있습니다. 함수 안에 함수를 정의하는 걸 처음 보신 분도 있을 수 있는데요. 하지만 파이썬에서는 전혀 이상하지 않습니다.
파이썬에서 함수는 function 이라는 클래스의 인스턴스입니다. 여러분이 클래스를 정의하고 클래스로 인스턴스를 만드는 것처럼, 함수를 정의하면 파이썬에 내장된 function 이라는 클래스의 인스턴스가 됩니다. 그렇기 때문에 우리가 인스턴스로 했던 모든 작업을 함수로도 할 수 있습니다.
인스턴스 안에 다른 인스턴스를 속성으로 가질 수 있듯이, 여기서도 quick_fix 라는 인스턴스가 result라는 인스턴스를 갖고 있는 것 뿐입니다. 함수라고 해서 특히 다르거나 이상할 게 없다는 뜻입니다. 이 부분이 이해되신다면 데코레이터가 어렵지 않으실 거에요.
마지막으로 저런 정부 정책의 변화가 있는 경우에 굳이 데코레이터를 쓸 필요없이 is_speeding 함수의 내용을 아래처럼 고치면 되는 거 아닌가라고 생각하시는 분도 계실 겁니다.
def is_speeding(speed, standard): if speed > standard: print('적발! 제한 속도 {}km/h 초과'.format(speed-standard)) return True else: return False print(is_speeding(150, 110)) print(is_speeding(100, 110))
네, 사실 맞습니다. 굳이 데코레이터를 쓰지 않고 위 코드처럼 고쳐도 됩니다. 사실 어느 방식으로 해도 큰 상관은 없습니다. 하지만 만약
(1) is_speeding 함수의 내용이 아주 복잡해서 변경할 부분을 찾기 어렵거나,
(2) is_speeding 의 코드는 변화가 없을 것으로 예상되지만 정부 정책이 자꾸 바뀔 것으로 예상되는 경우에는 그냥 데코레이터를 쓰는 것이 나을 겁니다.
상황에 따라 여러분이 판단하실 문제죠. 하지만 만약, 기존 함수의 내용을 건드리지 않고 어떤 기능을 추가만 하고 싶을 때는 데코레이터가 유용할 겁니다.
데코레이터가 뭔지 이 글을 읽고 이해가 잘 되셨나요? 오늘 배운 내용을 잘 기억하신다면, 파이썬에 내장된 데코레이터나 다른 개발자가 쓴 데코레이터를 마주칠 때 당황하지 않고 대처하실 수 있을 겁니다.
파이썬으로 배우는 프로그래밍 기초가 더 궁금한다면, 코드잇에서 72시간 무료로 체험해보세요 :-)