### 九步学会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`。通过这种方式,我们可以根据传入的参数来改变装饰器的行为。这种结构是实现更复杂装饰器的基础。
- 粉丝: 11
- 资源: 869
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助