~~~
wrapper ['ræpə] n.包装;
~~~
[如何理解Python装饰器? - 刘志军的回答 - 知乎 ](https://www.zhihu.com/question/26930016/answer/99243411)
[详解Python的装饰器](https://www.cnblogs.com/cicaday/p/python-decorator.html)
`decorator`:返回函数的高阶函数
参数是函数,返回是函数。
定义
-----
**作用**:为函数增加额外功能
**应用场景**:有切面需求的场景,如:插入日志、性能测试、事务处理、缓存、权限校验等
**好处**:可以抽离出大量与函数功能本身无关的雷同代码并继续重用(重用:装饰多个类同函数)
#### 完整装饰器写法:
1、返回内函数(包裹原函数和装饰程序,内函数替代原函数)
2、内函数的返回值是原函数的执行结果
3、复制原函数内置属性到内函数(functools.wraps)
**tips**:
1) *装饰器接口约束*:装饰器本身必须是callable对象(如函数,重载__call__的类),返回一个callable对象
- 返回callable对象并非指最终返回结果,而是指第一个return返回的内层包裹
- 个别情况不返回callable对象,如内置装饰器@property
3) 装饰器函数在原函数之前定义
~~~
# @语法糖:
# 原函数变量 = 执行:装饰器
#
# foo = deco(foo) = wrapper
# foo(...) = wrapper(...) = 原foo(...)
import functools
def deco(func):
@functools.wraps(func) # 复制属性
def wrapper(*args, **kwargs): # wrapper可接收任意参数
pass # do something
return func(*args, **kwargs) # func执行wrapper接收的任意参数
return wrapper
@deco # foo = deco(foo)
def foo(arg1, arg2):
return arg1 + arg2
res = foo(1, 2) # 同:wrapper(1,2) 同:do something后执行原foo(1,2)
print(foo.__name__)
~~~
@
---
语法糖@作用等同如下:
~~~
# 该例子也是一个装饰器,只不过代码没有使用@优雅
# 显然该装饰器无法接受参数
def debug(func):
def wrapper():
print(f'[DEBUG]: enter {format(func.__name__)}()')
return func()
return wrapper
def say_hello():
print('hello!')
say_hello = debug(say_hello) # 添加功能并保持原函数名不变
say_hello()
# 输出:
# [DEBUG]: enter say_hello()
# hello!
~~~
为什么返回内函数
---------------------
直接返回原函数:
装饰代码仅在返回原函数时执行了一次,以后即不会再执行。
~~~
def deco(func):
print('hello') # decorator code:something else to do
return func
@deco
def foo(arg1, arg2):
return arg1 + arg2
print(foo(1,2))
print(foo(3,4))
''' 输出:
hello
3
7
'''
~~~
functools.wraps
-------------------
使用`functools.wraps`复制原函数内置属性到内函数。
`wraps`本身也是`functools`模块的一个装饰器。
~~~
# 不使用装饰器
def foo():
pass
print(foo.__name__) # foo
~~~
~~~
# 装饰器改动了原函数的某些属性
def deco(func):
def wrapper(*args, **kwargs):
pass # do something ...
return func(*args, **kwargs)
return wrapper
@deco
def foo():
pass
print(foo.__name__) # wrapper
~~~
- 前言
- Python编程规范
- 编码
- 代码
- 缩进、行宽、引号、空行
- 空格
- 换行
- import
- 注释
- 代码注释
- 文档注释(Docstring)
- 命名规范
- 数据结构
- 变量
- 变量作用域
- 命名空间
- 作用域
- python作用域
- 对象
- 序列
- 可迭代对象
- 迭代器
- 生成器
- 可迭代对象 & 迭代器 & 生成器
- 整数池 & 字符串intern
- 数据类型
- 数字
- int
- float
- NaN
- 四舍五入 & 取整
- 列表
- 元组
- 字典
- 集合
- 字符串
- 字符集&字符编码
- 字符串&字节串
- 字符串函数
- 字符串格式化
- str.format
- Formatted string literals
- format函数
- string.Formatter类
- %
- Format String Syntax
- Format Specification Mini-Language
- fill
- align
- sign
- #
- 0
- width
- grouping_option
- .precision
- type
- locale
- Python3 locale 模块
- 语句
- 运算符
- if/else
- for...in
- while
- break/continue
- 函数
- 函数
- 函数参数
- 递归函数
- 匿名函数
- 高阶函数
- map
- reduce
- filter
- sorted
- 返回函数
- 闭包
- 装饰器
- 函数装饰器
- 带参数的装饰器
- 类装饰器
- 带参数的类装饰器
- 偏函数
- 面向对象
- 类 & 实例
- 属性
- 方法
- 访问限制
- 继承
- 新式类 & 经典类
- MRO
- MixIn
- 模块
- 特殊变量
- 编写模块
- 引入 & 重载
- 搜索模块
- 第三方模块
- 常见模块
- 标准库
- os
- sys
- datetime
- re
- urllib
- time/datetime
- threading
- multiprocessing
- builtins
- help
- range
- enumerate
- 异同
- str() repr() ascii()
- exit()、sys.exit()、os._exit()
- 数据库
- mysql
- 错误、调试、测试
- 异常
- 异常处理
- 自定义异常
- 抛出异常
- 调试
- logging
- pdb
- 线程&&进程
- 线程
- 杂
- python 脚本传参
- python无关
- redis
- mongo
- linux
- mysql简略