python中的类装饰器应用场景_Python装饰器17-将装饰器类应用于类的成员函数

本文探讨了如何将装饰器类应用于Python类的成员函数,并分析了在此过程中遇到的问题。通过示例代码展示了如何利用`__get__`和`__call__`方法实现正确的装饰器行为。同时,解释了`types.MethodType`的作用,帮助理解类装饰器在成员函数上下文中的工作原理。
摘要由CSDN通过智能技术生成

有没有可能将装饰器类应用于类的成员函数呢?根据之前的分析,似乎是可以的,代码:

from functools import wraps

class Profiled:

def __init__(self, func):

wraps(func)(self)

def __call__(self, *args, **kwargs):

print("call")

return self.__wrapped__(*args, **kwargs)

class Spam:

@Profiled

def bar(self, x):

print(self, x)

s = Spam()

s.bar(1)

执行结果:

call

Traceback (most recent call last):

File "decorator146.py", line 21, in

s.bar(1)

File "decorator146.py", line 12, in __call__

return self.__wrapped__(*args, **kwargs)

TypeError: bar() missing 1 required positional argument: 'x'

似乎出现了问题。

当装饰器类应用于类成员函数时,类成员函数变成什么样了?

from functools import wraps

class Profiled:

def __init__(self, func):

wraps(func)(self)

def __call__(self, *args, **kwargs):

print("call")

return self.__wrapped__(*args, **kwargs)

class Spam:

@Profiled

def bar(self, x):

print(self, x)

s = Spam()

print(s)

print(s.bar)

print(s.__dict__)

print(Spam.__dict__)

运行结果:

<__main__.Spam object at 0x7f363ceae550>

<__main__.Profiled object at 0x7f363d10d6a0>

{}

{'__module__': '__main__', 'bar': <__main__.Profiled object at

0x7fd313c686a0>, '__dict__': ,

'__weakref__': , '__doc__':

None}

发现此时bar的属性竟然变为一个类的属性!

非常类似通过以下代码定义的Spam

class Spam:

bar = Profiled()

此时我们继续理解之前将类作为装饰器应用于成员函数时。

s.bar(1)

调用分为2个步骤:

s.bar 获取bar的类实例

s.bar(1),对类实例进行调用

第一条需要根据之前所描述,需要实现__get__函数

第二条需要实现__call__属性

备注:其实包含3步,还有一步是__init__

正确的方法

import types

from functools import wraps

class Profiled:

def __init__(self, func):

wraps(func)(self)

def __call__(self, *args, **kwargs):

print("call")

return self.__wrapped__(*args, **kwargs)

def __get__(self, instance, cls):

if instance is None:

print('1')

print(self)

return self

else:

print('2')

print(types.MethodType(self, instance))

return types.MethodType(self, instance)

class Spam:

@Profiled

def bar(self, x):

print(self,x)

s = Spam()

# print(s)

# print(s.bar)

# print(s.__dict__)

# print(Spam.__dict__)

s.bar(1)

运行结果:

2

>

call

<__main__.Spam object at 0x7fc08562c5c0> 1

结果是预期的,

至于__get__函数的三个参数的意义详解可以参考Python官网文档,这里只是大概说明

instance表示所在的类,上述代码就是Spam,cls参数指的就是Profiled

至于types.MethodType表示的意义就是什么就查看官网文档就行。

当然这里还有一些问题似乎无法理解,继续看看types.MethodType等就可以理解。这里不再累述了。

小结

将装饰器类应用于类的成员函数其实是最复杂的场景,当然装饰器应用的场景远不止提到的这几种,在里就介绍了很多种,可以看看教材中其余装饰器的使用,不过基本原理就是连载里所提到的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值