Python 함수 장식 기 사용 튜 토리 얼

전형 적 인 함수 장식 기
다음 예제 에 서 는 장식 기,출력 함수 의 운행 시간 을 정의 합 니 다.

함수 장식 기와 패 킷 이 밀접 하 게 결합 되 어 있 으 며,인삼 func 에 들 어가 면 장식 함 수 를 대표 하 며,자유 변 수 를 통 해 연 결 된 후 함 수 를 호출 하여 결 과 를 되 돌려 줍 니 다.
clock 장식 기 사용:

import time
from clockdeco import clock

@clock
def snooze(seconds):
    time.sleep(seconds)

@clock
def factorial(n):
    return 1 if n < 2 else n*factorial(n-1)

if __name__=='__main__':
    print('*' * 40, 'Calling snooze(.123)')
    snooze(.123)
    print('*' * 40, 'Calling factorial(6)')
    print('6! =', factorial(6))  # 6! 6   
출력 결과:

이것 은 장식 기의 전형 적 인 행위 이다.장 식 된 함 수 를 새로운 함수 로 바 꾸 고 두 사람 은 같은 매개 변 수 를 받 아들 이 며 장 식 된 함수 가 되 돌아 가 야 할 값 을 되 돌려 주 는 동시에 추가 작업 도 할 수 있다.
주의해 야 할 것 은 factorial()은 재 귀 함수 입 니 다.결 과 를 보면 재 귀 할 때마다 장식 기 를 사용 하여 운행 시간 을 인쇄 했 습 니 다.이것 은 다음 과 같은 코드 때 문 입 니 다.

@clock
def factorial(n):
    return 1 if n < 2 else n*factorial(n-1)
등가:

def factorial(n):
    return 1 if n < 2 else n*factorial(n-1)
    
factorial = clock(factorial)
factorial 은 clock(factorial)함수 의 반환 값,즉 장식 기 내부 함수 clocked 를 참조 합 니 다.factorial(n)을 호출 할 때마다 clocked(n)를 실행 합 니 다.
인 테 리 어

@d1
@d2
def f():
    print("f")
등가:

def f():
    print("f")

f = d1(d2(f))
매개 변수 화 장식 기
어떻게 장식 기 에 인 자 를 받 아들 입 니까?정 답 은 장식 기 공장 함 수 를 만 들 고 인 자 를 전달 하 며 장식 기 를 되 돌려 주 고 장식 할 함수 에 적용 하 는 것 이다.
예 는 다음 과 같다.

registry = set()

def register(active=True):
    def decorate(func):
        print('running register(active=%s)->decorate(%s)'
              % (active, func))
        if active:
            registry.add(func)
        else:
            registry.discard(func)

        return func
    return decorate

@register(active=False)
def f1():
    print('running f1()')

#        
@register()
def f2():
    print('running f2()')

def f3():
    print('running f3()')
register 는 장식 기 공장 함수 입 니 다.선택 가능 한 매개 변수 active 를 받 아들 이 는 기본 값 은 True 이 고 내부 에 장식 기 decorate 를 정의 하여 되 돌려 줍 니 다.주의해 야 할 것 은 장식 기 공장 함수 입 니 다.파 라 메 터 를 전달 하지 않 더 라 도 작은 괄호 호출 을 추가 해 야 합 니 다.예 를 들 어@register().
예 를 하나 더 보 자.

import time

DEFAULT_FMT = '[{elapsed:0.8f}s] {name}({args}) -> {result}'

#        
def clock(fmt=DEFAULT_FMT):
    #       
    def decorate(func): 
        #         
        def clocked(*_args):
            t0 = time.time()
            # _result             
            _result = func(*_args)  
            elapsed = time.time() - t0
            name = func.__name__
            args = ', '.join(repr(arg) for arg in _args) 
            result = repr(_result) 
            # **locals()  clocked     
            print(fmt.format(**locals()))  
            return _result 
        return clocked  
    return decorate 

if __name__ == '__main__':

    @clock()  
    def snooze(seconds):
        time.sleep(seconds)

    for i in range(3):
        snooze(.123)
이것 은 전형 적 인 함수 장식 기 에 매개 변수 fmt 를 추가 한 것 으로 장식 기 공장 함수 에 포 함 된 세트 를 추가 하 였 으 며,예제 에는 모두 3 개의 def 가 있다.
표준 라 이브 러 리 의 장식 기
Python 은 장식 방법 에 사용 할 세 가지 함 수 를 내장 하 였 습 니 다:property,classmethod,staticmethod.이것 은 미래의 글 에서 말 할 것 입 니 다.본 고 는 funtools 중의 세 가지 장식 기 를 소개 한다.funtools.wraps,funtools.lrucache 와 funtools.singledispatch.
functools.wraps
Python 함수 장식 기 가 실 현 될 때 장 식 된 함 수 는 이미 다른 함수(함수 명 등 함수 속성 이 변 경 됩 니 다)입 니 다.영향 을 주지 않 기 위해 Python 의 funtools 패키지 에 wraps 라 는 장식 기 를 제공 하여 이러한 부작용 을 제거 합 니 다(기 존 함수 의 이름과 함수 속성 을 유지 할 수 있 습 니 다).
예제,wraps 를 추가 하지 않 음:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        '''decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def example():
    """Docstring"""
    print('Called example function')

print(example.__name__, example.__doc__)
#   wrapper decorator
wraps 추가:

import functools


def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        '''decorator'''
        print('Calling decorated function...')
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def example():
    """Docstring"""
    print('Called example function')

print(example.__name__, example.__doc__)
#   example Docstring
functools.lru_cache
lru 는 Least Recently Used 의 줄 임 말로 최적화 기술 로 시간 이 걸 리 는 함수 의 결 과 를 저장 하여 같은 매개 변수 가 들 어 올 때 중복 계산 하지 않도록 합 니 다.
예시:

import functools

from clockdeco import clock

@functools.lru_cache()
@clock
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-2) + fibonacci(n-1)

if __name__=='__main__':
    print(fibonacci(6))
재 귀 알고리즘 을 최적화 하면 실행 시간 이 반 으로 줄어든다.
주의,lrucache 는 두 개의 선택 가능 한 매개 변 수 를 사용 하여 설정 할 수 있 습 니 다.서명 은 다음 과 같 습 니 다.

functools.lru_cache(maxsize=128, typed=False)
4.567917.maxsize:최대 저장 수량,캐 시 가 가득 차 면 오래된 결 과 는 버 려 집 니 다4.567917.typed:True 로 설정 하면 서로 다른 매개 변수 유형 에서 얻 은 결 과 를 분리 하여 저장 합 니 다.즉,보통 같은 부동 소수점 과 정형 매개 변수(예 를 들 어 1 과 1.0)를 구분 합 니 다functools.singledispatch
Python 3.4 의 새로운 문법 은 함수 중의 대량의 if/elif/elif 를 최적화 하 는 데 사용 할 수 있 습 니 다.@singledispatch 장식 을 사용 하 는 일반 함 수 는 범 함수 가 됩 니 다.첫 번 째 매개 변수 유형 에 따라 같은 동작 을 수행 하 는 함수 입 니 다.그래서 싱글 디 스 패 치,단일 분파 라 고 합 니 다.
여러 매개 변수 에 따라 분 파 를 하면 다 분 파 를 하 는 것 이다.
예 를 들 어 HTML 을 생 성하 고 서로 다른 유형의 Python 대상 을 표시 합 니 다.

import html


def htmlize(obj):
    content = html.escape(repr(obj))
    return '<pre>{}</pre>'.format(content)
Python 은 리 셋 방법 이나 함 수 를 지원 하지 않 기 때문에 서로 다른 서명 으로 htmlize 의 변 체 를 정의 할 수 없습니다.htmlize 를 하나의 분파 함수 로 만 들 수 있 습 니 다.if/elif/elif 를 사용 하여 전문 적 인 함 수 를 호출 할 수 있 습 니 다.예 를 들 어 htmlizestr、htmlize_int 등.시간 이 길 어 지면 htmlize 가 커 지고 각 전문 함수 와 의 결합 도 긴밀 하여 모듈 확장 에 불편 합 니 다.
@singledispatch 는 심사숙고 한 끝 에 표준 라 이브 러 리 에 가입 하여 이러한 문 제 를 해결 합 니 다.

from functools import singledispatch
from collections import abc
import numbers
import html

@singledispatch
def htmlize(obj):
    #          if/elif/elif    
    content = html.escape(repr(obj))
    return '<pre>{}</pre>'.format(content)

@htmlize.register(str)
def _(text):
    #     
    content = html.escape(text).replace('
', '<br>
') return '<p>{0}</p>'.format(content) @htmlize.register(numbers.Integral) def _(n): # return '<pre>{0} (0x{0:x})</pre>'.format(n) @htmlize.register(tuple) @htmlize.register(abc.MutableSequence) def _(seq): # inner = '</li>
<li>'.join(htmlize(item) for item in seq) return '<ul>
<li>' + inner + '</li>
</ul>'
@singledispatch 가 기본 함 수 를 장식 하 였 습 니 다.전문 함수 사용@.register(>)장식 입 니 다.이름 은 중요 하지 않 습 니 다.이름 은 입 니 다.간단명료 하 다.
이렇게 코드 를 작성 하면 Python 은 첫 번 째 매개 변수의 유형 에 따라 해당 하 는 전문 함 수 를 호출 합 니 다.
작은 매듭
본 고 는 먼저 전형 적 인 함수 장식 기 를 소개 했다.장 식 된 함 수 를 새로운 함수 로 바 꾸 고 두 사람 은 똑 같은 매개 변 수 를 받 아들 이 며 장 식 된 함수 가 되 돌아 가 야 할 값 을 되 돌려 주 는 동시에 추가 작업 도 할 것 이다.이 어 장식 기의 두 가지 고급 용법 을 소개 했다.장식 기와 파라미터 화 장식 기 를 중첩 하면 함수 의 내장 등급 을 증가 할 것 이다.마지막 으로 3 개의 표준 라 이브 러 리 의 장식 기 를 소개 합 니 다.기 존 함수 속성 을 유지 하 는 funtools.wraps,캐 시 에 걸 린 함수 결과 의 funtools.lrucache 와 if/elif/elif 코드 를 최적화 한 funtools.singledispatch.
참고 자료:
《유창 한 파 이 썬》https://github.com/fluentpython/example-code/tree/master/07-closure-deco
https://blog.csdn.net/liuzonghao88/article/details/103586634
이상 은 Python 함수 장식 기 고급 용법 의 상세 한 내용 입 니 다.Python 함수 장식 기 용법 에 관 한 자 료 는 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기