티스토리 뷰
🥨 데커레이터(decorator)는 무엇인가
함수 데커레이터는 소스 코드에 있는 함수를 '표시'해서 함수의 작동을 개선할 수 있게 해준다.
1. 데커레이터는 데커레이트된 함수를 다른 함수로 대체하는 능력이 있다.
2. 데커레이터는 모듈이 로딩될 때 바로 실행된다.
대부분의 데커레이터는 데커레이트된 함수를 변경한다.
즉, 내부 함수를 정의하고 그것을 반환하여 데커레이트된 함수를 대체한다.
내부 함수를 사용하는 코드는 제대로 작동하기 위해 거의 항상 클로저에 의존한다.
🥨 파이썬이 데커레이터를 실행하는 시점
데커레이터의 핵심 특징은 데커레이트된 함수가 정의된 직후에 실행된다는 것이다.
이는 일반적으로 파이썬이 모듈을 로딩하는 시점, 즉 임포트 타임에 실행된다.
함수 데커레이터는 모듈이 임포트되자마자 실행되지만, 데커레이트된 함수는 명시적으로 호출될 때만 실행된다.
임포트 타임과 런타임은 다르다 !!
🥨 클로저 closure
클로저는 함수 본체에서 정의하지 않고 참조하는 비전역nonglobal 변수를 포함한 확장 범위를 가진 함수다.
함수가 익명 함수인지 여부는 중요하지 않다.
함수 본체 외부에 정의된 비전역 변수에 접근할 수 있다는 것이 중요하다.
클로저는 함수를 정의할 때 존재하던 자유 변수(지역 범위에 바인딩되어 있지 않은 변수)에 대한 바인딩을 유지하는 함수다.
따라서 함수를 정의하는 범위가 사라진 후에 함수를 호출해도 자유변수에 접근할 수 있다.
🥨 nonlocal 선언
파이썬 3에 새롭게 추가되었다.
변수를 nonlocal로 선언하면 함수 안에서 변수에 새로운 값을 할당하더라도 그 변수는 자유 변수임을 나타낸다.
새로운 값을 nonlocal 변수에 할당하면 클로저에 저장된 바인딩이 변경된다.
-> 이러한 기능이 필요한 이유는 숫자, 문자열, 튜플 등 불변형은 읽을 수만 있고 값을 갱신할 수는 없다.
그래서 불변형 변수를 수정하게 되면 암묵적으로 지역변수를 새롭게 생성하게 되고, 그럼 자유변수가 아니게 되므로
클로저에 저장되지 않는다.
그럼 파이썬 2에서는 nonlocal 기능이 없으므로 다른 방법이 있었을텐데.. 과연 어떤 방법을 이용했을까?
생각해보면 꽤 본질적이고 근본적인 해결방법이 있다.
내부 함수에서 변경해야 하는 변수를 가변 객체(dict나 간단한 객체)의 항목이나 속성으로 저장하고,
그 객체를 자유변수에 바인딩한다.
🥨 간단한 데커레이터 구현하기
전형적인 데커레이터의 작동 방식
1. 데커레이트된 함수를 동일한 인수를 받는 함수로 교체한다.
2. 일반적으로 데커레이트된 함수가 반환해야 하는 값을 반환하면서, 추가적인 처리를 수행한다.
import time
import functools
def clock(func):
@functools.wraps(func)
def clocked(*args, **kwargs):
t0 = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - t0 # 소요 시간
name = func.__name__
arg_list = []
if args:
arg_list.append(', '.join(repr(arg) for arg in args))
if kwargs:
pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
arg_list.append(', '.join(pairs))
arg_str = ','.join(arg_list)
print('[%0.8fs] %s(%s) -> %r' % (elapsed, name, arg_str, result))
return result
return clocked
from clockdeco import clock
@clock
def factorial(n):
return 1 if n < 2 else n*factorial(n-1)
if __name__=='__main__':
print('6! = ', factorial(6))
🥨 표준 라이브러리에서 제공하는 데커레이터
파이썬에서는 메서드를 데커레이트하기 위해 property(), classmethod(), staticmethod() 등 총 3개의 내장 함수를 제공한다.
이 내장함수들은 나중에 자세히 알아보겠다~~~
1. @functools.wraps()
: 제대로 작동하는 데커레이터를 만들기 위한 헬퍼이다. 키워드 인수를 지원하고, 데커레이트된 함수를 데커레이트 내부 함수로 관련된 속성을 복사한다.
2. @functools.lru_cache(maxsize=128, typed=False)
: 메모이제이션을 구현한다. 메모이제이션은 이전에 실행한 값비싼 함수의 결과를 저장함으로써 이전에 사용된 인수에 대해 다시 계산할 필요가 없게 해준다. LRU(Least Recently Used) Cache는 오랫동안 사용하지 않은 항목을 버림으로써 캐시가 무한정 커지지 않음을 의미한다. 재귀 알고리즘 또는 웹에서 정보를 가져와야 하는 애플리케이션 등에서 주로 사용한다.
maxsize 인수는 얼마나 많은 호출을 저장할지 결정한다. typed 인수는 True로 설정되는 경우 인수의 자료형이 다르면 결과를 따로 저장한다.
3. @functools.singledispatch()
: 파이썬에서는 메서드나 함수의 오버로딩을 지원하지 않으므로, 서로 다르게 처리하고자 하는 의도별로 서로 다른 시그니처를 가진 메서드나 함수를 만들 수 없다.
파이썬 3.4에서 새로 소개된 functools.singledispatch() 데커레이터는 각 모듈이 전체 해결책에 기여할 수 있게 해주며,
편집할 수 없는 클래스에 대해서도 특화된 함수를 쉽게 제공할 수 있게 해준다.
일반 함수를 @singledispatch 로 데커레이트하면, 이 함수는 범용함수(generic function)가 된다.
이때, 제네릭 함수란 어떤 하나의 함수가 여러 타입의 인자를 받고, 인자의 타입에 따라 적절한 동작을 하는 함수를 의미한다.
파이썬은 동적 타입 언어이기 때문에 언어수준의 명시적인 제네릭 지원 기능은 없다.
🥨 매개변수화된 데커레이터
소스 코드에서 데커레이터를 파싱할 때 파이썬은 데커레이트된 함수를 가져와서 데커레이터 함수의 첫 번째 인수로 넘겨준다.
그러면 어떻게 다른 인수를 받는 데커레이터를 만들 수 있을까?
인수를 받아 데커레이터를 반환하는 데커레이터 팩토리를 만들고 나서, 데커레이트될 함수에 데커레이터 팩토리를 적용하면 된다.
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 정적멤버
- method와 function
- 백준
- yarn start
- 익명자식객체
- Git
- jdk
- 자바스레드
- 자바빌드도구
- 사용자정의예외클래스
- @functools.singledispatch
- ES6
- dynamic-project
- 자바스크립트Promise
- 백준2206 파이썬 풀이
- 클래스와객체
- 메이븐 저장소
- sequelize.fn
- 인스턴스멤버
- nodejs
- nunjucks
- 자바스크립트Call-back
- jre
- @functools.lru_cache
- java
- 생성자필드메소드
- os
- @functools.wraps
- es6모듈
- 객체지향개념
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함