博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2015/9/29 Python基础(20):类的授权
阅读量:5218 次
发布时间:2019-06-14

本文共 4526 字,大约阅读时间需要 15 分钟。

类的授权

1.包装
包装在Python编程世界中时经常会被提到的一个术语。它是一个通用的名字,意思是对一个已存在的对象进行包装,不管它是数据类型,还是一段代码,可以是对一个已存在的对象,增加新的,删除不要的,或者修改其他已存在的功能。
在Python2.2以前,从Python的标准类型子类化或派生类都是不允许的,即使你现在可以这么做,这种做法也并不多。你可以包装任何类型作为一个类的核心成员,以使新对象的行为模仿你想要的数据类型中已存在的行为,并且去掉你不希望存在的行为;它可能会要做一些额外的事情。这就是“包装类型”。在附录中,我们还将讨论如何扩充Python,包装的另一种形式。
包装包括定义一个类,它的实例拥有标准类型的核心行为,但它也通过新的或最新的功能,甚至可能通过访问实际数据的不同方法得到提高。
还可以包装类,但这不会有太大的用途,因为已经有拥有操作对象的机制,并且在之前已经描述过,我们采用派生对标准类型有对其进行包装的方式。

2.实现授权

授权是包装的一个特性,可用于简化处理有关dictating功能,采用已存在的功能达到最大限度的代码重用。
包装一个类型通常是对已存在的类型的一些定制。我们在前面提到过,这种方法可以新建,修改或者删除原有产品的功能。其它的则保持原样,或者保留已存功能和行为。授权的过程,即是所有更新的功能都是有新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__()方法,在代码中包含一个对getattr()内建函数的调用。特别地,调用getattr()以得到默认对象属性(数据属性或者方法)并返回它以便访问或调用。特殊方法__getattr__()的工作方式是,当搜索一个属性时,任何局部对象(定制的对象)首先被找到。如果搜索失败了,则__getattr__()会被调用。然后调用getattr()得到一个对象的默认行为。
也就是说,引用一个属性时,Python解释器将试着在局部名称空间中查找那个名字,比如一个自定义的方法或者局部实例属性。如果没有在局部字典中找到,则搜索类名称空间,以防一个类属性被访问。最后,如果两类搜索都失败了,搜索对原对象开始授权请求,此时,__getattr__()会被调用。

包装对象的简例

这个类几乎可以包装任何对象,提供基本功能。比如使用repr()和str()来处理字符串表示法, 定制由get()方法处理,它删除包装并且返回原始对象,所以保留的功能都授权给对象的本地属性,在必要时,可又__getattr__()获得。

>>> class WrapMe(object):  def __init__(self, obj):    self.__data = obj  def get(self):    return self.__data  def __repr__(self):    return `self.__data`  def __str__(self):    return str(self.__data)  def __getattr__(self, attr):    return getattr(self.__data, attr)

 

我们使用复数来举第一个例子,因为复数有数据属性及conjugate()内建方法。

>>> wrappedComplex = WrapMe(3.3+1.2j)>>> wrappedComplex(3.3+1.2j)>>> wrappedComplex.real3.3>>> wrappedComplex.imag1.2>>> wrappedComplex.conjugate()(3.3-1.2j)>>> wrappedComplex.get()(3.3+1.2j)

 

一旦我们创建了包装的对象类型,只要由交互解释器调用repr(),就可以得到一个字符串表示,然后我们访问了复数的三种属性,而这在类中一种都没有定义。对这种属性的访问,是通过__getattr__()方法,授权给对象。最终调用的get()方法没有授权,因为它是为我们对象单独定义的。

然后是一个列表的例子

>>> wrappedList = WrapMe([123, 'foo', 45.67])>>> wrappedList.append('bar')>>> wrappedList.append(123)>>> wrappedList[123, 'foo', 45.67, 'bar', 123]>>> wrappedList.index(45.67)2>>> wrappedList.count(123)2>>> wrappedList.pop()123>>> wrappedList[123, 'foo', 45.67, 'bar']

注意,尽管我们正在我们的例子中使用实例,它们展示的行为与他们包装的数据类型非常相似。然后需要明白,只有已存在的属性是在此代码中授权的。
但是也不是所有的行为都能被访问,比如:

>>> wrappedList[3]Traceback (most recent call last):File "
", line 1, in
wrappedList[3]TypeError: 'WrapMe' object does not support indexing

对于列表的索引切片操作,它是内建于类型中的,而不是像append()方法那样作为属性存在的。所以不能被访问。从另一个角度来说,切片操作符是序列类型的一部分,并不是通过__getitem__()这样的特殊方法来实现的。

我们有一种“作弊”的方法,访问实际对象,然后用它的切片能力:

>>> realList = wrappedList.get()>>> realList[3]'bar'

这就是我们实现get()方法的原因了,我们可以从访问调用中直接访问对象的属性,而忽略局部变量。

这里是简单包装类的例子。我们还刚开始接触使用类型模拟来进行类自定义。你将会发现你可以进行无限多的改进,来进一步增加代码的用途。

更新简单的包裹类

创建时间,修改时间,及访问时间是文件的几个常见属性。我们将给一个类添加时间属性,创建时间('ctime')是实例化的时间,修改时间('mtime')是核心数据升级的时间,而访问时间('atime')是最后一次对象数据值被获取或者属性被访问的时间戳。
我们更新前面定义的类,创建一个模块twrapme.py
代码如下:

from time import time, ctimeclass TimeWrapMe(object):    def __init__(self, obj):        self.__data = obj        self.__ctime = self.__mtime = \               self.__atime = time()     def get(self):        self.__atime = time()        return self.__data    def gettimeval(self, t_type):        if not isinstance(t_type, str) or \           t_type[0] not in 'cma':            raise TypeError, \                  "argument of 'c', 'm', or 'a' req'd"        return getattr(self, '_%s__%stime' % \                       (self.__class__.__name__, t_type[0]))            def gettimestr(self, t_type):        return ctime(self.gettimeval(t_type))    def set(self, obj):        self.__data = obj        self.__mtime = self.atime = time()        def __repr__(self):        self.__atime = time()        return `self.__data`    def __str__(self):        self.__atime = time()        return str(self.__data)    def __getattr__(self, attr):        self.__atime = time()        return getattr(self.__data, attr)

 

测试如下:

>>> TimeWrappedObj = TimeWrapMe(123)>>> TimeWrappedObj.gettimestr('c')'Tue Sep 29 17:25:11 2015'>>> TimeWrappedObj.gettimestr('m')'Tue Sep 29 17:25:11 2015'>>> TimeWrappedObj.gettimestr('a')'Tue Sep 29 17:25:11 2015'>>> TimeWrappedObj123>>> TimeWrappedObj.gettimestr('c')'Tue Sep 29 17:25:11 2015'>>> TimeWrappedObj.gettimestr('m')'Tue Sep 29 17:25:11 2015'>>> TimeWrappedObj.gettimestr('a')'Tue Sep 29 17:25:26 2015'>>> TimeWrappedObj.set('Update time!')>>> TimeWrappedObj.gettimestr('m')'Tue Sep 29 17:28:06 2015'>>> TimeWrappedObj'Update time!'>>> TimeWrappedObj.gettimestr('c')'Tue Sep 29 17:25:11 2015'>>> TimeWrappedObj.gettimestr('m')'Tue Sep 29 17:28:06 2015'>>> TimeWrappedObj.gettimestr('a')'Tue Sep 29 17:28:19 2015'

 

转载于:https://www.cnblogs.com/SRL-Southern/p/4848590.html

你可能感兴趣的文章
Ubuntu安装Flash
查看>>
Frenetic Python实验(二)
查看>>
Android 对话框(Dialog)大全 建立你自己的对话框 分类: An...
查看>>
Linux进程管理(3):总结
查看>>
Android 用HorizontalScrollView实现ListView的Item滑动删除 ,滑动错乱 冲突
查看>>
HDU6438 Buy and Resell
查看>>
configure/make/make install的作用
查看>>
墨菲定律、二八法则、马太效应、手表定理、“不值得”定律、彼得原理、零和游戏、华盛顿合作规律、酒与污水定律、水桶定律、蘑菇管理原理、钱的问题、奥卡姆剃刀等13条是左右人生的金科玉律...
查看>>
beanutils中类型转换
查看>>
java 拾遗
查看>>
在Bonobo服务器里创建Repository(库)
查看>>
ImageSharp一个专注于NetCore平台图像处理的开源项目
查看>>
Windows Management Instrumentation 服务无法启动 解决办法
查看>>
Problem B: 时间类的错误数据处理
查看>>
bzoj 1754: [Usaco2005 qua]Bull Math【高精乘法】
查看>>
bzoj 4753: [Jsoi2016]最佳团体【01分数规划+二分+树上背包】
查看>>
Python3基础知识之元组、集合、字典
查看>>
更多的开发经验
查看>>
用于获取或设置Web.config/*.exe.config中节点数据的辅助类
查看>>
设计模式(十九)—— 备忘录模式
查看>>