데코레이터
이전 기사에서는 요구 사항 문제를 해결하여 클로저에 대해 배웠습니다. 이 기사에서는 요구 사항을 천천히 발전시키고 Python 데코레이터를 단계별로 이해함으로써 동일한 작업을 수행합니다.
먼저 직원 출근 정보를 출력하는 기능이 있습니다.
def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') punch()
출력 결과는 다음과 같습니다.
昵称:两点水 部门:做鸭事业部 上班打卡成功
그럼 제품 피드백, 아니 왜 출근 날짜가 따로 정해져 있지 않나요? 작업, 출근의 특정 날짜를 추가해야 합니다. 이 작업은 매우 간단하며 몇 분 안에 해결할 수 있습니다. 좋아요, 그러면 다음과 같이 날짜를 인쇄하는 코드를 추가하세요.
import time def punch(): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) print('昵称:两点水 部门:做鸭事业部 上班打卡成功') punch()
출력 결과는 다음과 같습니다.
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功
이렇게 변경해도 괜찮지만 이 함수가 다음과 같은 경우 함수의 기능적 구조가 변경됩니다. 정의되면 직원의 정보와 프롬프트가 성공적으로 인쇄됩니다. 이제 날짜를 인쇄하기 위해 코드를 추가하면 많은 코드 중복 문제가 발생할 수 있습니다. 예를 들어, 직원 정보를 인쇄하고 성공적으로 펀치만 하면 되지만 날짜는 요구하지 않는 또 다른 곳이 있으므로 함수를 다시 작성해야 합니까? 또한, 현재 날짜를 출력하는 이러한 함수형 방식은 자주 사용되며, 각 모듈 방식에 대한 공용 함수로 호출할 수 있습니다. 물론 이는 모두 전체 프로젝트로 간주된다.
이런 경우에는 함수형 프로그래밍을 사용하여 코드의 이 부분을 수정할 수 있습니다. 이전 연구를 통해 Python 함수에는 두 가지 특성이 있다는 것을 알고 있습니다. 함수는 함수 내에 중첩될 수 있습니다. 그런 다음 코드를 다음과 같이 수정합니다. 맞나요? 이렇게 하면 펀치 방법이 변경되지 않으며 현재 날짜를 인쇄해야 하는 모든 함수는 다음과 같이 함수를 add_time에 전달할 수 있습니다.
import time def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') def add_time(func): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() add_time(punch)
결과 인쇄:
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功
쉽나요? 함수 프로그래밍을 사용하려면 편리하지만 호출할 때마다 원래 함수를 매개변수로 전달해야 합니다. 이를 구현하는 더 좋은 방법이 있습니까? 네, 이번 글에서 소개할 것이 바로 데코레이터입니다. 데코레이터를 작성하는 방법은 사실 클로저와 비슷하지만, 자유변수가 없기 때문에 위의 코드에서 데코레이터를 작성하는 방법은 이렇습니다. 비교를 위해 글쓰기와 함수형 프로그래밍의 차이점은 무엇입니까?
import time def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') def add_time(func): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() def holiday(): print('天气太冷,今天放假') add_time(punch) add_time(holiday)
출력 결과:
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功 2018-01-09 天气太冷,今天放假
코드를 통해 데코레이터 함수가 일반적으로 다음 세 가지 작업을 수행한다는 것을 알 수 있습니다.
함수를 매개변수로 받습니다.
래퍼 함수를 중첩하고 래퍼 함수는 동일한 매개변수를 받습니다. 그리고 원래 함수도 실행하고, 추가 함수도 실행
중첩 함수 반환
그런데 이 코드를 잘 살펴보면 함수형 프로그래밍보다 이 데코레이터를 작성하는 방식이 왜 더 까다로운 걸까요? 그리고 복잡해 보이고, 심지어 조금 불필요해 보이기도 합니다.
아직 데코레이터의 "syntax sugar"를 사용하지 않았기 때문입니다. 위의 코드를 보면 Python이 데코레이터(Decorator)를 도입했을 때 새로운 구문 기능을 도입하지 않았음을 알 수 있습니다. 함수 구문 특성. 이는 또한 데코레이터가 Python에만 고유한 것이 아니라 모든 언어에 공통된 프로그래밍 아이디어임을 보여줍니다. 단지 Python이 데코레이터를 정의하고 데코레이터를 원래 함수로 호출하고 결과를 원래 함수의 객체 이름에 더 간단하고 편리하며 조작하기 쉽게 할당하는 과정을 만드는 @ 구문 설탕을 설계했기 때문입니다. Python 데코레이터의 구문 설탕이라고 말할 수 있습니다.
그렇다면 구문 설탕을 어떻게 사용할까요? 위의 작성방법에 따라 데코레이터 함수를 작성한 후 원래 함수에 @와 데코레이터의 함수명을 직접 추가하면 됩니다. 다음과 같습니다:
import time def decorator(func): def punch(): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() return punch def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') f = decorator(punch) f()
출력 결과:
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功
그러면 이는 호출에 매우 편리합니다. 예를 들어 이 예에서는 데코레이터를 사용한 후 원래 함수에 데코레이터의 구문 설탕을 직접 추가할 수 있습니다. 이 기능에는 변경 사항이 없으며 호출 위치를 수정할 필요가 없습니다.
그러나 여기에는 항상 문제가 있었습니다. 즉, 펀치인 정보의 출력이 고정되어 있으므로 데코레이터를 어떻게 작성해야 할까요? 데코레이터의 함수는 *args 변수 매개변수를 사용할 수 있지만 *args를 사용하는 것만으로는 모든 매개변수를 완전히 포함할 수 없습니다. 예를 들어 키워드 매개변수와 호환하려면 **kwargs 도 추가해야 합니다.
따라서 데코레이터의 최종 형태는 다음과 같이 작성할 수 있습니다.
import time def decorator(func): def punch(): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() return punch @decorator def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') punch()
출력 결과는 다음과 같습니다.
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功
이것이 Python 시작에 관한 일련의 기사의 끝입니다.