九步学会Python装饰器
需积分: 0 102 浏览量
更新于2020-09-22
收藏 47KB PDF 举报
### 九步学会Python装饰器
#### 第一步:最简单的函数,准备附加额外功能
我们从一个非常基础的函数开始,这个函数没有任何额外的功能,仅仅是打印一条消息表明它被调用了。
```python
def myfunc():
print("myfunc() called.")
```
这个函数在调用时会输出`myfunc() called.`。为了添加额外的功能,比如记录函数调用的时间或者增加日志等,我们需要考虑使用装饰器。
#### 第二步:使用装饰函数在函数执行前和执行后分别附加额外功能
接下来,我们创建了一个装饰器`deco`,用于在调用`myfunc`之前和之后添加额外的行为:
```python
def deco(func):
def _deco():
print("before myfunc() called.")
func()
print("after myfunc() called.")
return _deco
@deco
def myfunc():
print("myfunc() called.")
myfunc()
```
在这个例子中,`deco`接受一个函数作为参数,并返回一个新的函数`_deco`。`_deco`会在调用`func`前后分别执行特定的操作。
#### 第三步:使用语法糖@来装饰函数
为了简化装饰器的使用,Python提供了语法糖`@decorator`的形式,这样就不需要显式地将函数赋值给装饰后的版本:
```python
def deco(func):
def _deco():
print("before myfunc() called.")
func()
print("after myfunc() called.")
return _deco
@deco
def myfunc():
print("myfunc() called.")
myfunc()
```
这里需要注意的是,如果装饰后的函数没有被再次调用,则装饰器内部的功能只会在第一次调用时生效。
#### 第四步:使用内嵌包装函数来确保每次新函数都被调用
为了避免上述问题,我们需要修改装饰器内的函数,使其成为真正的包装函数,保留原始函数的所有行为:
```python
def deco(func):
def _deco():
print("before myfunc() called.")
result = func()
print("after myfunc() called.")
return result
return _deco
@deco
def myfunc():
print("myfunc() called.")
return "OK"
myfunc()
```
现在,`_deco`不仅在调用`func`前后执行了额外的操作,还正确地返回了`func`的结果。
#### 第五步:对带参数的函数进行装饰
对于带有参数的函数,我们需要相应地修改装饰器内部的包装函数,以便能够传递这些参数:
```python
def deco(func):
def _deco(a, b):
print("before myfunc() called.")
result = func(a, b)
print("after myfunc() called. result: %s" % result)
return result
return _deco
@deco
def myfunc(a, b):
print("myfunc(%s, %s) called." % (a, b))
return a + b
myfunc(1, 2)
```
#### 第六步:对参数数量不确定的函数进行装饰
当函数接受可变数量的参数时,可以使用`*args`和`**kwargs`来接收这些参数,并在装饰器中正确地处理它们:
```python
def deco(func):
def _deco(*args, **kwargs):
print("before %s called." % func.__name__)
result = func(*args, **kwargs)
print("after %s called. result: %s" % (func.__name__, result))
return result
return _deco
@deco
def myfunc(a, b):
print("myfunc(%s, %s) called." % (a, b))
return a + b
@deco
def myfunc2(a, b, c):
print("myfunc2(%s, %s, %s) called." % (a, b, c))
return a + b + c
myfunc(1, 2)
myfunc2(1, 2, 3)
```
#### 第七步:让装饰器带参数
为了让装饰器本身具有更大的灵活性,我们可以为装饰器添加参数,从而实现不同的行为:
```python
def deco(arg):
def _deco(func):
def __deco(*args, **kwargs):
print("before %s called with %s." % (func.__name__, arg))
result = func(*args, **kwargs)
print("after %s called. result: %s" % (func.__name__, result))
return result
return __deco
return _deco
@deco("test")
def myfunc(a, b):
print("myfunc(%s, %s) called." % (a, b))
return a + b
myfunc(1, 2)
```
这里的`deco`是一个高阶函数,它接收一个参数并返回一个装饰器`_deco`。`_deco`又接收一个函数作为参数,并返回真正的包装函数`__deco`。通过这种方式,我们可以根据传入的参数来改变装饰器的行为。这种结构是实现更复杂装饰器的基础。
weixin_38672815
- 粉丝: 11
- 资源: 869
最新资源
- 单片机温度控制器,基于pid算法的半导体温控系统 PID智能温控系统proteus仿真,能升温、降温、控温;LCD显示设置温度与实时温度;请悉知,资料包含程序源码(stm32库函数),Proteus
- GD链条-模块对应表(X1)
- java(选修)复习资料.7z
- (cuda12.4)mamba-ssm-2.2.2-cp310-cp310-win-amd64.whl
- google-chrome-stable-current-x86-64.rpm
- 一套WPF+.net6 WebApiv+SqlSugar ORM 权限管理平台源代码,全源码,仅限系统管理部分源代码C#WPF也是当前智能制造企业研发工控系统研发的首选,这套系统也是学习与研发的首选
- GD链条-模块对应表(X2)
- 2. java-TM(实例源码+习题答案).rar
- google chrome 64位-98.0.4758.82.exe
- 数组冒泡排序程序 博途v16编写的西门子排序程序,可实现不同长度的数组排序,可根据需求选择从大到小还是从小到大排序 封装好的FC块直接可以拿来学习,并且配有注释可轻松学习
- Cursor小工具 需要一定动手能力的友友下载
- 3. java-PPT课件(可供参考).rar
- 全国水体分布shp矢量数据集
- GDL语言中文说明使用书
- 一种粒子群优化算法优化深度极限学习机DELM中的各极限学习机中自动编码器的输入权重与偏置,建立PSO-DELM回归预测模型,多输入单输出模型,时间窗法,代码注释清晰,替数据简单,只需替自己的excel
- 舒尔特方格 暑期学校mfc大作业 mfc.zip