데코레이터를 배우기 전에 클로저의 개념을 이해해야 합니다. 클로저 형성의 핵심 포인트:
다음은 계산하는 경우 클로저를 설명하기 위한 목록의 평균 패키지:
def make_average(): # 创建一个列表,用来保存数值 nums = [] # 定义一个内部函数,用来计算列表的平均值 def average(n): # 将数值添加到列表中 nums.append(n) # 返回平均值 return sum(nums) / len(nums) return average
# 调用外部函数,并将其复制给一个变量,注意:此时返回的是内函数的内存地址 a = make_average() # 给这个变量加(),就相当于调用了内函数average print(a(20)) print(a(30))
실행 결과는 다음과 같습니다. 전달된 값이 20이면 목록에 숫자가 하나만 있으므로 계산 결과는 20이고, 다른 값 30이 전달되면 20과 30이라는 두 개의 숫자가 있습니다. 이므로 평균을 계산한 결과는 25입니다.
예를 들어, 두 숫자의 합과 점수를 계산하는 두 가지 함수가 있습니다. 각각:
def add(a, b): """计算两数之和""" res = a + b return res def mul(a, b): """计算两数之积""" res = a * b return res
이제 요구 사항이 있습니다. 각 함수의 계산이 시작되기 전에 "계산 시작..."을 인쇄하고, 계산이 끝난 후에 "계산 종료..."를 인쇄하고 싶습니다. 함수 코드를 직접 수정하여 이러한 요구를 충족할 수 있지만 다음과 같은 문제에 직면하게 됩니다.
그래서 위의 기능 코드를 직접 수정하는 방법은 불가능합니다. 우리는 원래 기능을 수정하지 않고 기능을 확장하기를 희망합니다. 예:
def new_add(a, b): print("开始计算...") r = add(a, b) print("计算结束...") return r print(new_add(22, 33))
실행 결과는 다음과 같습니다.
이 새 함수 생성 방법은 원래 함수를 수정하지 않지만 매우 심각한 문제에 직면합니다.
지정된 함수만 확장할 수 있고 확장할 수 없습니다. 예를 들어, 위의 add 함수는 확장할 수 없지만 mul 함수를 확장하려면 확장 함수만 생성하면 됩니다. 모든 기능의 범위를 지정할 수 있는 범용 확장 기능입니다. 원래 함수 코드를 변경하지 않는 이러한 유형의 범용 함수는 데코레이터입니다.
2. 함수 데코레이터
1) 장식된 함수는 매개변수를 사용하지 않습니다
def wrapper_info(func): def inner(): print("开始介绍...") res = func() print("介绍结束...") return res return inner def introduce1(): print("我是周润发,我来自HONG KONG") info = wrapper_info(introduce1) info()
실행 결과는 다음과 같습니다.
원본 함수 코드를 변경하지 않고 일부 추가 함수가 원래 함수, func 데코레이션할 함수입니다. 데코레이션 함수에 변수로 전달되며 다른 함수에도 보편적으로 사용할 수 있습니다. 하지만 현재 문제는 장식된 함수가 매개변수를 취하는 경우 어떻게 될까요? 예:
def introduce2(name, age): print(f"我叫{name}, 我今年{age}岁了")
2) 데코레이팅된 함수에는 매개변수가 있습니다
이때 가변 길이 매개변수를 사용해야 합니다: (*args, **kwargs)
def wrapper_info(func): """ 用来对其他函数进行扩展,使其他函数可以在执行前做一些额外的动作 :param func: 要扩展的函数对象 :return: """ def inner(*args, **kwargs): print("开始介绍...") res = func(*args, **kwargs) print("介绍结束...") return res return inner
예:
def introduce3(name, age, city): print(f"我叫{name}, 我今年{age}岁了, 我来自{city}")
실행 결과는 다음과 같습니다.
上述提到的是装饰器,一种是应用于被装饰的函数不带参数,一种是被装饰的函数带参数,那装饰器本身能否带参数呢?比如我定义一个变量,想通过传入不同的值来控制这个装饰器实现不同的功能。答案是肯定的,例如:
def use_log(level): def decorator(func): def inner(*args, **kwargs): if level == "warn": logging.warning("%s is running by warning" % func.__name__) elif level == "info": logging.warning("%s is running by info" % func.__name__) else: logging.warning("%s is running by other" % func.__name__) return func(*args, **kwargs) return inner return decorator def introduce4(name, age, city): print(f"我叫{name}, 我今年{age}岁了, 我来自{city}") info1 = use_log(introduce4('周星驰', 28, '香港')) info1('info') info2 = use_log(introduce4('周润发', 28, '香港')) info2('warn') info3 = use_log(introduce4('成龙', 28, '香港')) info3('xxx')
运行结果如下:
info3 = wrapper_info(introduce3) info3('刘德华', 28, '香港')
如果是装饰器函数带参数,则调用方式为:
info4 = use_log(introduce4('周星驰', 28, '香港')) info4('info')
即在被装饰函数上方以@符号进行修饰
@wrapper_info def introduce3(name, age, city): print(f"我叫{name}, 我今年{age}岁了, 我来自{city}") introduce3('刘德华', 28, '香港')
如果是装饰器函数带参数,例如上述的use_log,则需要在装饰器中传入参数:
@use_log('info') def introduce4(name, age, city): print(f"我叫{name}, 我今年{age}岁了, 我来自{city}")
在不改变原函数代码的情况下,给原函数增加了一些额外的功能,并且能够通用于其他函数,这样的函数就称作为装饰器。
可以通过传统调用函数的方式进行调用,也可以通过@装饰器的方式调用
위 내용은 Python 데코레이터 - 클로저 및 함수 데코레이터의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!