Python闭包与装饰器核心机制及实战解析
本文深入解析Python中闭包与装饰器的核心机制。详细阐述闭包的三个构成条件,并系统介绍装饰器的定义、执行顺序、带参数实现、基于类的实现方式以及内置装饰器如@property的用法。通过具体代码示例,帮助开发者掌握如何利用装饰器扩展函数功能,提升代码复用性与可维护性。
闭包
Python支持函数的嵌套定义。当内部函数引用了外部函数(非全局作用域)中的变量时,该内部函数即被称为闭包。
要构成闭包,需同时满足以下三个条件:
1. 存在两个嵌套的函数结构,且闭包特指内部函数;
2. 内部函数引用了外部函数的变量(即自由变量);
3. 外部函数将内部函数的名称作为返回值返回。
具体示例如下:

装饰器
1、装饰器本质上是一个Python函数,其作用是在不修改原函数代码的前提下,为其增加额外功能,且装饰器的返回值也是一个函数对象。它常用于处理切面需求,例如插入日志、性能测试、事务处理、缓存机制或权限校验等。装饰器是解决此类问题的优秀设计模式,通过它可以将与核心功能无关的重复代码抽离出来并重用。
2、装饰器作为一个函数,必须接收一个参数,该参数代表被修饰的目标函数。
例如,定义如下一个装饰器函数:
def w1(func):
print(‘正在装饰')
def inner():
print(‘正在验证权限')
return inner()- 装饰器本质上是一个嵌套函数结构。
- 其中,内部函数构成了一个闭包。
- 外部函数接收的参数是被修饰的函数(func)。
3、在函数定义前添加@符号及装饰器名称,即可实现对该函数的包装。
为f1函数添加装饰器的示例如下:
@w1
def f1():
print('f1')此时,程序在编译阶段会自动生成调用装饰器函数的代码,其效果等价于: f1 = w1(f1)
多个装饰器
当多个装饰器应用于同一个函数时,其执行顺序是从下至上依次进行。
@w1
@w2
def f1():
print(‘---f1---')具体的执行顺序为:先执行@w2,后执行@w1
带参数的装饰器
假设前文的装饰器不仅需要记录进入函数时的日志,还需要指定日志的级别,那么装饰器的实现形式将发生变化。
def logging(level):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
print "[{level}]: enter function {func}()".format(
level=level,
func=func.__name__)
return func(*args, **kwargs)
return inner_wrapper
return wrapper
@logging(level='INFO') def say(something):
print "say {}!".format(something)
# 如果没有使用@语法,等同于
# say = logging(level='INFO')(say)
@logging(level='DEBUG') def do(something):
print "do {}...".format(something)
if __name__ == '__main__':
say('hello')
do("my work")- 当带参数的装饰器应用于某个函数时,例如@logging(level=‘DEBUG’),这实际上是一个立即执行的函数。只要该函数返回的结果是一个有效的装饰器,即可正常工作。
基于类实现的装饰器
装饰器函数遵循特定的接口约束:它必须接受一个callable对象作为参数,并返回一个callable对象。
在Python中,callable对象通常指函数,但也存在例外。只要某个对象重载了__call__()方法,该对象即为callable。
class Test():
def __call__(self):
print 'call me!'
t = Test()
t() # call me像__call__这样前后带有双下划线的方法,在Python中被称为内置方法,有时也被称作魔法方法。
重载这些魔法方法通常会改变对象的内部行为。上述示例展示了如何让一个类对象具备被调用的行为。
回到装饰器的概念,它要求接受一个callable对象,并返回一个callable对象(此描述较为宽泛,详细情况见后文)。
因此,使用类来实现装饰器也是可行的。我们可以让类的构造函数__init__()接收一个函数,随后重载__call__()方法并返回一个函数,从而达到与普通装饰器函数相同的效果。
class logging(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print "[DEBUG]: enter function {func}()".format(
func=self.func.__name__)
return self.func(*args, **kwargs)
@logging
def say(something):
print "say {}!".format(something)带参数的类装饰器
若需通过类形式实现带参数的装饰器,实现过程会相对复杂。此时,构造函数接收的不再是函数,而是传入的参数,并通过类将这些参数保存下来。在重载__call__方法时,需接收一个函数并返回一个函数,以此实现装饰器功能。
class logging(object):
def __init__(self, level='INFO'):
self.level = level
def __call__(self, func): # 接受函数
def wrapper(*args, **kwargs):
print "[{level}]: enter function {func}()".format(
level=self.level,
func=func.__name__)
func(*args, **kwargs)
return wrapper #返回函数
@logging(level='INFO')
def say(something):
print "say {}!".format(something)内置的装饰器
内置装饰器与普通装饰器的原理相同,区别在于其返回的是类对象而非函数。在理解此装饰器之前,需了解不使用装饰器时如何定义属性。
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
# create a property
x = property(getx, setx, delx, "I am doc for x property")上述代码展示了Python属性的标准写法,其逻辑与Java相似,但代码较为繁琐。使用@语法糖可以实现相同效果,且代码更为简洁。
@property def x(self): ... # 等同于 def x(self): ... x = property(x)
带有返回值的装饰器
def func(functionName):
def func_in():
return functionName()
return func_in
@func def test():
return ‘itheima'至此,关于Python中闭包与装饰器用法的详解介绍完毕。如需了解更多Python装饰器相关内容,建议搜索本站历史文章或继续阅读后续相关文章,感谢大家的支持!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









