概念
装饰器本质:接收函数作为参数,返回新函数 ,在不修改原函数代码、不改变原函数调用方式 的前提下,给函数新增功能(日志、计时、权限、缓存、重试等)。
它允许你修改函数或类的行为,而不更改其源代码。实质上,装饰器是接受另一个函数作为参数并返回一个包装原始函数的新函数。这样,你可以在不修改原始函数的情况下,添加一些额外的功能或逻辑。
def time_cost(func):
"""
:return:
"""
def wrapper(*args, **kwargs):
"""
:param args:
:param kwargs:
:return:
"""
start = int(time.time() * 1000)
func(*args, **kwargs)
end = int(time.time() * 1000)
print("call api time cost:%s ms" %
(end - start))
return wrapper
python
def ntimes(n):
def inner(f):
def wrapper(*args, **kwargs):
for _ in range(n):
rv = f(*args, **kwargs)
return rv
return wrapper
return inner
#然后你可以使用上述函数包装另一个函数,例如前文中的 add 函数:
@ntimes(3)
def add(x, y):
print(x + y)
return x + y
最简单装饰器(无参装饰器)
写法 1:原生嵌套函数(理解原理)
# 定义装饰器
def decorator(func):
# 内层包装函数
def wrapper():
print("执行前:新增逻辑")
func() # 调用原函数
print("执行后:新增逻辑")
return wrapper
# 普通函数
def say_hello():
print("Hello World")
# 手动装饰
say_hello = decorator(say_hello)
# 调用(调用的是 wrapper)
say_hello()
写法 2:语法糖 @(工程常用)
不用手动赋值,@装饰器名 放在函数上方 ,等价于 func = decorator(func)
def decorator(func):
def wrapper():
print("前置逻辑")
func()
print("后置逻辑")
return wrapper
# 语法糖装饰
@decorator
def say_hello():
print("Hello World")
say_hello()
Python中有许多内置的装饰器
例如@staticmethod、@classmethod、@property、@functools.lru_cache、@functools.singledispatch等。你还可以为不同的目的创建自己的自定义装饰器。
闭包函数
闭包函数就是定义在函数内部的函数,也就是函数的嵌套定义,根据字面意思理解,闭包函数有两个关键字闭和包分别是的封闭和包裹。需要注意的重点是:闭包函数的作用域关系在函数定义阶段就固定死了,与调用位置无关。
1.什么是闭包函数:一个函数的返回值是另外一个函数,返回的函数调用父函数内部的变量,如果返回的函数在外部被执行,就产生了闭包
2.闭包函数的作用:使函数外部能够调用函数内部放入属性和方法
3.闭包函数的优缺点:
优点:使函数外部能够调用函数内部放入属性和方法
缺点:闭包操作导致整个函数的内部环境被长久保存,占用大量内存
__closure__属性。Python给内部函数添加了这个属性来携带内部函数用到的外部函数中的变量。

闭包作用
数据隐藏
闭包可以创建私有变量,避免全局污染。外部无法直接访问闭包内部的变量,只能通过闭包暴露的方法操作。
javascript
const module = (function() {
let privateVar = 0;
function privateMethod() {
return privateVar;
}
return {
publicMethod: function() {
return privateMethod();
}
};
})();
console.log(module.publicMethod()); // 输出 0
DRY 原则
模块化开发
闭包是实现模块化的重要方式,通过返回对象或函数暴露接口,隐藏内部实现细节。
延长变量生命周期
外部函数的变量在执行后通常会被销毁,但闭包会保留对这些变量的引用,使其存活时间更长。
javascript
function delayLog(msg, time) {
setTimeout(function() {
console.log(msg); // 闭包保留了msg的引用
}, time);
}
delayLog("Hello", 1000); // 1秒后输出 "Hello"
函数柯里化
闭包可以用于柯里化(Currying),将多参数函数转换为单参数链式调用。
javascript
function add(x) {
return function(y) {
return x + y;
};
}
const add5 = add(5);
console.log(add5(3)); // 输出 8
闭包函数使用场景
- 封装:这种场景叫做封装。
- 内部函数可以方便的生成新的函数
- 装饰器:对Python至关重要。这也是内部函数的主要使用场景。