本文是装饰器相关内容的第二篇,关于类装饰器。

"类装饰器"有两种解读方式:用来装饰类的装饰器;类作为装饰器装饰其它东西。你如何认为取决于你,两种说法都有出现在其它的文章中。我的文章中是将"类装饰器"解读为第一种方式,即装饰类的东西。而“类作为装饰器装饰其它东西”,我都会为其标注"类作为装饰器"或"作为装饰器的类"以避免歧义。

类装饰器的形式

函数装饰器是装饰函数(方法)的,类装饰器是装饰类的,它们的表现形式是一样的。

@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)

最新文章

  1. Keepalived+LVS+nginx双机热备
  2. Nginx + Tomcat Windows下的负载均衡配置
  3. 1005. Spell It Right (20)
  4. cxTreeList 控件说明
  5. Linux常用系统调用
  6. Angularjs学习---ubuntu12.04中karma安装配置
  7. Xml转化为DataTable
  8. ggplot2 geom设置—散点图
  9. Extending sparklyr to Compute Cost for K-means on YARN Cluster with Spark ML Library
  10. Quartz + Tablesaw 报表统计
  11. Dynamics CRM 电子邮件服务器配置文件Advanced配置中关闭SSL
  12. VsCode调试js
  13. LeetCode Monotone Stack Summary 单调栈小结
  14. Python定期删除文件、整理文件夹
  15. 软件工程导论课后习题Github作业(把一个英文句子中的单词次序逆序,单词中字母正常排列)
  16. Sublime Text 3(中文)在Windows下的配置、安装、运行
  17. WPF c# 定时器
  18. asp.net 练习 js 调用webservice
  19. POJ2104 K-th Number 不带修改的主席树 线段树
  20. Winform中的Treeview动态绑定数据库

热门文章

  1. Notes : <Hands-on ML with Sklearn & TF> Chapter 6
  2. unic
  3. python3--迭代
  4. mybatis注解SQL
  5. python猜数字GUI版本V0.1
  6. shell实例利用crontab自动清除日志
  7. JAVA RSA加密AES加密
  8. 透彻讲解,Java线程的6种状态及切换
  9. Javascript高级编程学习笔记(48)—— HTML5
  10. PHP新特性Trait