python进阶装饰器_老生常谈Python进阶之装饰器

函数也是对象

要理解Python装饰器,首先要明白在Python中,函数也是一种对象,因此可以把定义函数时的函数名看作是函数对象的一个引用。既然是引用,因此可以将函数赋值给一个变量,也可以把函数作为一个参数传递或返回。同时,函数体中也可以再定义函数。

装饰器本质

可以通过编写一个纯函数的例子来还原装饰器所要做的事。

def decorator(func):

def wrap():

print("Doing someting before executing func()")

func()

print("Doing someting after executing func()")

return wrap

def fun_test():

print("func")

fun_test = decorator(fun_test)

fun_test()

# Output:

# Doing someting before executing func()

# func

# Doing someting after executing func()

fun_test所指向的函数的引用传递给decorator()函数

decorator()函数中定义了wrap()子函数,这个子函数会调用通过func引用传递进来的fun_test()函数,并在调用函数的前后做了一些其他的事情

decorator()函数返回内部定义的wrap()函数引用

fun_test接收decorator()返回的函数引用,从而指向了一个新的函数对象

通过fun_test()调用新的函数执行wrap()函数的功能,从而完成了对fun_test()函数的前后装饰

Python中使用装饰器

在Python中可以通过@符号来方便的使用装饰器功能。

def decorator(func):

def wrap():

print("Doing someting before executing func()")

func()

print("Doing someting after executing func()")

return wrap

@decorator

def fun_test():

print("func")

fun_test()

# Output:

# Doing someting before executing func()

# func

# Doing someting after executing func()

装饰的功能已经实现了,但是此时执行:

print(fun_test.__name__)

# Output:

# wrap

fun_test.__name__已经变成了wrap,这是应为wrap()函数已经重写了我们函数的名字和注释文档。此时可以通过functools.wraps来解决这个问题。wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

更规范的写法:

from functools import wraps

def decorator(func):

@wraps(func)

def wrap():

print("Doing someting before executing func()")

func()

print("Doing someting after executing func()")

return wrap

@decorator

def fun_test():

print("func")

fun_test()

print(fun_test.__name__)

# Output:

# Doing someting before executing func()

# func

# Doing someting after executing func()

# fun_test

带参数的装饰器

通过返回一个包裹函数的函数,可以模仿wraps装饰器,构造出一个带参数的装饰器。

from functools import wraps

def loginfo(info='info1'):

def loginfo_decorator(func):

@wraps(func)

def wrap_func(*args, **kwargs):

print(func.__name__ + ' was called')

print('info: %s' % info)

return func(*args, **kwargs)

return wrap_func

return loginfo_decorator

@loginfo()

def func1():

pass

func1()

# Output:

# func1 was called

# info: info1

@loginfo(info='info2')

def func2():

pass

func2()

# Output:

# func2 was called

# info: info2

装饰器类

通过编写类的方法也可以实现装饰器,并让装饰器具备继承等面向对象中更实用的特性

首先编写一个装饰器基类:

from functools import wraps

class loginfo:

def __init__(self, info='info1'):

self.info = info

def __call__(self, func):

@wrap

def wrap_func(*args, **kwargs):

print(func.__name__ + ' was called')

print('info: %s' % self.info)

self.after() # 调用after方法,可以在子类中实现

return func(*args, **kwargs)

return wrap_func

def after(self):

pass

@loginfo(info='info2')

def func1():

pass

# Output:

# func1 was called

# info: info1

再通过继承loginfo类,扩展装饰器的功能:

class loginfo_after(loginfo):

def __init__(self, info2='info2', *args, **kwargs):

self.info2 = info2

super(loginfo_after, self).__init__(*args, **kwargs)

def after(self):

print('after: %s' % self.info2)

@loginfo_after()

def func2():

pass

func2()

# Output:

# func2 was called

# info: info1

# after: info2

以上这篇老生常谈Python进阶之装饰器就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持聚米学院。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值