python装饰器2:类装饰器
本文是装饰器相关内容的第二篇,关于类装饰器。
"类装饰器"有两种解读方式:用来装饰类的装饰器;类作为装饰器装饰其它东西。你如何认为取决于你,两种说法都有出现在其它的文章中。我的文章中是将"类装饰器"解读为第一种方式,即装饰类的东西。而“类作为装饰器装饰其它东西”,我都会为其标注"类作为装饰器"或"作为装饰器的类"以避免歧义。
类装饰器的形式
函数装饰器是装饰函数(方法)的,类装饰器是装饰类的,它们的表现形式是一样的。
@decorator
class cls:
...
c = cls()
等价于:
class cls:
...
cls = decorator(cls)
c = cls()
它的效果是创建实例对象的时候,会触发装饰器中的代码逻辑。
再细细一想,发现decorator(cls)
要返回的是一个类,所以decorator中的结构大概是这样的:
def decorator(cls):
class wrapper:
...
return wrapper
这样就会让被包装的类cls实际变成wrapper类,并且以后调用cls构造对象的时候,实际上是调用wrapper类来构造对象。换句话说,wrapper已经拦截了对所有的cls操作。
但并非一定如此,比如直接返回原始的cls:
def decorator(cls):
...do something about cls...
return cls
这种方式比较简单,本文主要对前一种方式进行详细解释。
由于返回的是class wrapper
,那么它装饰类的时候,假设所装饰的类有构造方法__init__
,构造方法中有属性,这个类中还有方法。如下:
@decorator
class cls(): # 等价于cls = decorator(cls)
def __init__(self, x, y):
self.attrx = x
self.attry = y
def method(self):
return self.x, self.y
那么在包装器wrapper中,需要能够构造出这个对象,并且能够取得被包装类的对象属性、类属性。如下:
def decorator(cls):
class wrapper():
def __init__(self, *args, **kwargs):
self.wrapped = cls(*args, **kwargs)
def __getattr__(self, name):
return getattr(self.wrapped, name)
return wrapper
因为操作cls类的时候,实际上是在操作wrapper类。所以构造cls对象的时候:
c = cls(3, 4)
实际上是在调用wrapper(3, 4)
来构造对象,所以会执行wrapper里的__init__
。但类装饰器最终的目标是为了扩展类cls,所以在wrapper里必须得构造出cls的对象。上面采取的方式是通过cls()来构造cls对象,并放在wrapper对象的一个属性wrapped中。
因为cls已经被金蚕脱壳成了wrapper,所以要获取到cls的属性必须在wrapper中重写属性获取的方式。
下面是一个示例:
def decorator(cls):
class wrapper():
def __init__(self, *args, **kwargs):
self.wrapped = cls(*args, **kwargs)
def __getattr__(self, name):
return getattr(self.wrapped, name)
return wrapper
@decorator
class cls():
def __init__(self, x, y):
self.attrx = x
self.attry = y
def method(self):
return self.attrx, self.attry
c = cls(3, 4)
print(c.attrx)
print(c.attry)
print(c.method())
输出结果:
3
4
(3, 4)
相关文章
- Python 操作 Kafka --- kafka-python
- Python中对序列数据的汇总(collections模块)
- python基础之文件读写
- Python装饰器 [1]
- python 装饰器
- Python零基础入门,2分钟带你了解python
- 金三银四,你是跳槽还是跳坑?为什么要选择python
- 每天一个python小知识——如何在Python 3中转换数据类型
- python pip 解决下载速度慢
- Python装饰器由浅入深
- 【Python】【PyPI】twine模块打包python项目上传pypi
- Python Numpy 中的打印设置函数set_printoptions
- python学习之OpenCV-Python模块的部分应用示例(生成素描图和动漫图)
- Python基础必掌握的re模块支持的元字符9类使用详解
- 【华为OD机试真题 java、python】找等值元素(100%通过+复盘思路)
- python基础训练题2-元组,字典
- Python爬虫之Scrapy框架(案例练习)
- 华为OD机试 - 猴子爬山(Python)| 真题+思路+考点+代码+岗位
- 小学Python编程 ——迷宫
- Python 工具 之 Windows 上 python 虚拟环境的搭建与简单使用的相关说明
- Unity 工具 之 报错 Jenkins 执行/调用 Python 脚本,报错提示 ‘python‘ 不是内部或外部命令,也不是可运行的程序或批处理文件
- python装饰器
- Python运算符优先级
- 主流的Python领域和框架--转
- Python与Django项目开发,使用inspect、signature、装饰器进行参数检查,QuerySet转List、Dict,以及数据操作方法的二次封装,解决业务和数据存储之间的耦合
- [Python] count()方法