本文实例讲述了Python类装饰器。分享给大家供大家参考,具体如下:

编写类装饰器

类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例。

单体类

由于类装饰器可以拦截实例创建调用,所以它们可以用来管理一个类的所有实例,或者扩展这些实例的接口。

下面的类装饰器实现了传统的单体编码模式,即最多只有一个类的一个实例存在。

instances = {} # 全局变量,管理实例

def getInstance(aClass, *args):

if aClass not in instances:

instances[aClass] = aClass(*args)

return instances[aClass] #每一个类只能存在一个实例

def singleton(aClass):

def onCall(*args):

return getInstance(aClass,*args)

return onCall

为了使用它,装饰用来强化单体模型的类:

@singleton # Person = singleton(Person)

class Person:

def __init__(self,name,hours,rate):

self.name = name

self.hours = hours

self.rate = rate

def pay(self):

return self.hours * self.rate

@singleton # Spam = singleton(Spam)

class Spam:

def __init__(self,val):

self.attr = val

bob = Person('Bob',40,10)

print(bob.name,bob.pay())

sue = Person('Sue',50,20)

print(sue.name,sue.pay())

X = Spam(42)

Y = Spam(99)

print(X.attr,Y.attr)

现在,当Person或Spam类稍后用来创建一个实例的时候,装饰器提供的包装逻辑层把实例构建调用指向了onCall,它反过来调用getInstance,以针对每个类管理并分享一个单个实例,而不管进行了多少次构建调用。

程序输出如下:

Bob 400

Bob 400

42 42

在这里,我们使用全局的字典instances来保存实例,还有一个更好的解决方案就是使用Python3中的nonlocal关键字,它可以为每个类提供一个封闭的作用域,如下:

def singleton(aClass):

instance = None

def onCall(*args):

nonlocal instance

if instance == None:

instance = aClass(*args)

return instance

return onCall

当然,我们也可以用类来编写这个装饰器――如下代码对每个类使用一个实例,而不是使用一个封闭作用域或全局表:

class singleton:

def __init__(self,aClass):

self.aClass = aClass

self.instance = None

def __call__(self,*args):

if self.instance == None:

self.instance = self.aClass(*args)

return self.instance

跟踪对象接口

类装饰器的另一个常用场景是每个产生实例的接口。类装饰器基本上可以在实例上安装一个包装器逻辑层,来以某种方式管理其对接口的访问。

前面,我们知道可以用__getattr__运算符重载方法作为包装嵌入到实例的整个对象接口的方法,以便实现委托编码模式。__getattr__用于拦截未定义的属性名的访问。如下例子所示:

class Wrapper:

def __init__(self,obj):

self.wrapped = obj

def __getattr__(self,attrname):

print('Trace:',attrname)

return getattr(self.wrapped,attrname)

>>> x = Wrapper([1,2,3])

>>> x.append(4)

Trace: append

>>> x.wrapped

[1, 2, 3, 4]

>>>

>>> x = Wrapper({'a':1,'b':2})

>>> list(x.keys())

Trace: keys

['b', 'a']

在这段代码中,Wrapper类拦截了对任何包装对象的属性的访问,打印出一条跟踪信息,并且使用内置函数getattr来终止对包装对象的请求。

类装饰器为编写这种__getattr__技术来包装一个完整接口提供了一个替代的、方便的方法。如下:

def Tracer(aClass):

class Wrapper:

def __init__(self,*args,**kargs):

self.fetches = 0

self.wrapped = aClass(*args,**kargs)

def __getattr__(self,attrname):

print('Trace:'+attrname)

self.fetches += 1

return getattr(self.wrapped,attrname)

return Wrapper

@Tracer

class Spam:

def display(self):

print('Spam!'*8)

@Tracer

class Person:

def __init__(self,name,hours,rate):

self.name = name

self.hours = hours

self.rate = rate

def pay(self):

return self.hours * self.rate

food = Spam()

food.display()

print([food.fetches])

bob = Person('Bob',40,50)

print(bob.name)

print(bob.pay())

print('')

sue = Person('Sue',rate=100,hours = 60)

print(sue.name)

print(sue.pay())

print(bob.name)

print(bob.pay())

print([bob.fetches,sue.fetches])

通过拦截实例创建调用,这里的类装饰器允许我们跟踪整个对象接口,例如,对其任何属性的访问。

Spam和Person类的实例上的属性获取都会调用Wrapper类中的__getattr__逻辑,由于food和bob确实都是Wrapper的实例,得益于装饰器的实例创建调用重定向,输出如下:

Trace:display

Spam!Spam!Spam!Spam!Spam!Spam!Spam!Spam!

[1]

Trace:name

Bob

Trace:pay

2000

Trace:name

Sue

Trace:pay

6000

Trace:name

Bob

Trace:pay

2000

[4, 2]

示例:实现私有属性

如下的类装饰器实现了一个用于类实例属性的Private声明,也就是说,属性存储在一个实例上,或者从其一个类继承而来。不接受从装饰的类的外部对这样的属性的获取和修改访问,但是,仍然允许类自身在其方法中自由地访问那些名称。类似于Java中的private属性。

traceMe = False

def trace(*args):

if traceMe:

print('['+ ' '.join(map(str,args))+ ']')

def Private(*privates):

def onDecorator(aClass):

class onInstance:

def __init__(self,*args,**kargs):

self.wrapped = aClass(*args,**kargs)

def __getattr__(self,attr):

trace('get:',attr)

if attr in privates:

raise TypeError('private attribute fetch:'+attr)

else:

return getattr(self.wrapped,attr)

def __setattr__(self,attr,value):

trace('set:',attr,value)

if attr == 'wrapped': # 这里捕捉对wrapped的赋值

self.__dict__[attr] = value

elif attr in privates:

raise TypeError('private attribute change:'+attr)

else: # 这里捕捉对wrapped.attr的赋值

setattr(self.wrapped,attr,value)

return onInstance

return onDecorator

if __name__ == '__main__':

traceMe = True

@Private('data','size')

class Doubler:

def __init__(self,label,start):

self.label = label

self.data = start

def size(self):

return len(self.data)

def double(self):

for i in range(self.size()):

self.data[i] = self.data[i] * 2

def display(self):

print('%s => %s'%(self.label,self.data))

X = Doubler('X is',[1,2,3])

Y = Doubler('Y is',[-10,-20,-30])

print(X.label)

X.display()

X.double()

X.display()

print(Y.label)

Y.display()

Y.double()

Y.label = 'Spam'

Y.display()

# 这些访问都会引发异常

"""

print(X.size())

print(X.data)

X.data = [1,1,1]

X.size = lambda S:0

print(Y.data)

print(Y.size())

这个示例运用了装饰器参数等语法,稍微有些复杂,运行结果如下:

[set: wrapped <__main__.Doubler object at 0x03421F10>]

[set: wrapped <__main__.Doubler object at 0x031B7470>]

[get: label]

X is

[get: display]

X is => [1, 2, 3]

[get: double]

[get: display]

X is => [2, 4, 6]

[get: label]

Y is

[get: display]

Y is => [-10, -20, -30]

[get: double]

[set: label Spam]

[get: display]

Spam => [-20, -40, -60]

希望本文所述对大家Python程序设计有所帮助。

python类装饰器详解-Python类装饰器实现方法详解相关推荐

  1. python 归一化还原_对python3 一组数值的归一化处理方法详解

    1.什么是归一化: 归一化就是把一组数(大于1)化为以1为最大值,0为最小值,其余数据按百分比计算的方法.如:1,2,3.,那归一化后就是:0,0.5,1 2.归一化步骤: 如:2,4,6 (1)找出 ...

  2. java 多个类共用属性_java中读写Properties属性文件公用方法详解

    前言 大家都知道Java中有个比较重要的类Properties(Java.util.Properties),主要用于读取Java的配置文件,各种语言都有自己所支持的配置文件,配置文件中很多变量是经常改 ...

  3. python数据分析工资_python3对拉勾数据进行可视化分析的方法详解

    前言 上回说到我们如何把拉勾的数据抓取下来的,既然获取了数据,就别放着不动,把它拿出来分析一下,看看这些数据里面都包含了什么信息. 下面话不多说了,来一起看看详细的介绍吧 一.前期准备 由于上次抓的数 ...

  4. python 百度云文字识别 proxy_python使用百度文字识别功能方法详解

    介绍python使用百度智能去的文字识别功能,可以识别截图中的文,登陆路验证码等等., 登陆百度智能云,选择产品服务. 选择"人工智能"---文字识别. 点击创建应用. 如图下面有 ...

  5. python中str是什么_python的str()字符串类型的方法详解

    字符串一旦创建,不可修改,一旦修改或者拼接,都会造成重新生成字符串,因为内存存数据是一个挨着一个存的,如果增加一个字符串的话,之前的老位置只有一个地方,不够,这是原理性的东西,在其他语言里面也一样 7 ...

  6. [转载] python中svm的使用_Python中支持向量机SVM的使用方法详解

    参考链接: 使用Python中的支持向量机(SVM)对数据进行分类 {"moduleinfo":{"card_count":[{"count_phon ...

  7. python对sqlite增删改查_Python操作SQLite数据库的方法详解【导入,创建,游标,增删改查等】...

    本文实例讲述了python操作SQLite数据库的方法.分享给大家供大家参考,具体如下: SQLite简介 SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的 ...

  8. python中sleep函数用法_sleep函数函数介绍与使用方法详解

    在一些竞猜的网站中,如果我们需要做一个定时执行的功能,比如有一道题,在十秒之内要完成,否则显示"您已超时",如果完成,则跳转到下一道题上面,而这中间有一个十秒的停顿,这样的功能是怎 ...

  9. win7怎么看服务器文件管理,Win7库文件管理器怎么用 Win7库功能及其使用方法详解...

    使用window7的用户都会注意到,系统里有一个极具特色的功能--"库",库是win7系统借鉴Ubuntu操作系统而推出的文件管理模式.库的概念并非传统意义上的存放用户文件的文件夹 ...

  10. java线程池详解及五种线程池方法详解

    基础知识 Executors创建线程池 Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可,比如Executors.newFixedThreadPool(int nThrea ...

最新文章

  1. 10 行代码玩转 NumPy!
  2. linux 内存管理 Transparent HugePages 透明大页 简介
  3. 【计算理论】可判定性 ( 非确定性有限自动机的接受问题 | 证明 “非确定性有限自动机的接受问题“ 的可判定性 )
  4. Python,美国顶尖大学里最受欢迎的编程入门语言
  5. 时间格式化需要注意点不可使用本地时间
  6. 字符串匹配之KMP算法详解
  7. outputStream
  8. 中gcd函数_函数和模块的使用
  9. 2012年7月的主要目标
  10. Linux系统下如何设置IP地址?
  11. 关于使用Kaptcha验证码框架遇到的问题
  12. n个数中的最大值和最小值
  13. 从零开始,学习web前端之HTML5
  14. 38000词汇词根统计
  15. 蔚来、宁德时代的换电攻坚战
  16. C#获取电脑MAC地址(物理地址)的几种方法
  17. spider分布式引擎
  18. 操作无法完成因为文件已在syayem中打开怎么处理删除文件。
  19. 暴走gif失落的出处_暴走gif表情包 - 暴走gif微信表情包 - 暴走gifQQ表情包 - 发表情 fabiaoqing.com...
  20. 演示程序之打游戏 -- 慕司板IAP15

热门文章

  1. 【IT笔试面试题整理】 二叉树任意两个节点间最大距离
  2. hdu 1828 pku 1177 Picture
  3. 祝福我的朋友们五一玩的开心!
  4. MATLAB爬虫爬取股票数据
  5. 实验二:用机器指令和汇编指令编程
  6. CodeForces - 985F Isomorphic Strings
  7. session和cookie的应用场景和区别
  8. 前端(慕课网)笔记一
  9. Nginx安装、配置及使用总结
  10. css selector list