类的授权
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.real
3.3
>>> wrappedComplex.imag
1.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 "<pyshell#29>", line 1, in <module>
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, ctime
class 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'
>>> TimeWrappedObj
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: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'

2015/9/29 Python基础(20):类的授权的更多相关文章

  1. 2015/8/29 Python基础(3):数值

    数字提供了标量储存和直接访问,是不可更改类型,每次变更数值会产生新的对象.Python支持多种数字类型,包括整型.长整型.布尔型.双精度浮点.十进制浮点和复数.在Python中,变量并不是一个盒子,而 ...

  2. 二十六. Python基础(26)--类的内置特殊属性和方法

    二十六. Python基础(26)--类的内置特殊属性和方法 ● 知识框架 ● 类的内置方法/魔法方法案例1: 单例设计模式 # 类的魔法方法 # 案例1: 单例设计模式 class Teacher: ...

  3. 二十. Python基础(20)--面向对象的基础

    二十. Python基础(20)--面向对象的基础 1 ● 类/对象/实例化 类:具有相同属性.和方法的一类人/事/物 对象(实例): 具体的某一个人/事/物 实例化: 用类创建对象的过程→类名(参数 ...

  4. python基础——枚举类

    python基础——枚举类 当我们需要定义常量时,一个办法是用大写变量通过整数来定义,例如月份: JAN = 1 FEB = 2 MAR = 3 ... NOV = 11 DEC = 12 好处是简单 ...

  5. python基础——定制类

    python基础——定制类 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__len__()方 ...

  6. Python基础-类的探讨(class)

    Python基础-类的探讨(class) 我们下面的探讨基于Python3,我实际测试使用的是Python3.2,Python3与Python2在类函数的类型上做了改变 1,类定义语法  Python ...

  7. 2015/9/28 Python基础(19):类的定制和私有性

    用特殊方法定制类前面我们讲了方法的两个重要方面:首先,方法必须在调用前被绑定(到它们相应类的某个实例中):其次,有两个特殊方法可以分别作为构造器和解构器的功能,分别名为__init__()和__del ...

  8. 2015/9/17 Python基础(13):函数

    函数是对程序逻辑进行结构化或过程化的一种编程方法. Python的函数返回值当什么也不返回时,返回了None和大多数语言一样,Python返回一个值或对象.只是在返回容器对象时,看起来像返回多个对象. ...

  9. python基础(26):类的成员(字段、方法、属性)

    1. 字段 字段:包括普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同. 普通字段属于对象 静态字段属于类 字段的定义和使用: class Province: # ...

随机推荐

  1. ncnblogs.com的用户体验

    你是什么样的用户, 有什么样的心理, 对cnblogs 的期望值是什么? 我是一名普通的学生,上cnblogs的期望是发表博客完成老师布置的任务. 当你第一次使用cnblogs 的功能的时候, 碰到了 ...

  2. UVALive 6913 I Want That Cake 博弈+dp

    题目链接: http://acm.hust.edu.cn/vjudge/problem/96343 I Want That Cake Time Limit: 3000MS 64bit IO Forma ...

  3. goroutine与channels

    goroutine(协程) 大家都知道java中的线程Thread,golang没有提供Thread的功能,但是提供了更轻量级的goroutine(协程),协程比线程更轻,创办一个协程很简单,只需要g ...

  4. 1029对c语言文法的理解

    <程序>→<外部声明>|<程序><外部声明> <外部声明>→<函数定义>|<声明> <函数定义>→< ...

  5. 使用.bat文件运行ant的build.xml

    1.新建一个txt文件 2.复制下面命令到txt文件 echo "Start build..." call ant.bat -f "E:\build.xml" ...

  6. 从装饰者模式的理解说JAVA的IO包

    1. 装饰者模式的详解 装饰者模式动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性 的替代方案. 装饰者模式设计类之间的关系: 其 中Component是一个超类,ConcreteC ...

  7. 【Linux笔记】CentOS&RHEL YUM基础知识

    以下内容收集自网络,以作参考. 一.YUM是什么 YUM = Yellow dog Updater, Modified. 主要功能是更方便的添加/删除/更新RPM包. 它能自动解决包的倚赖性问题. 它 ...

  8. postman 上一个接口返回值传给下一个接口

    问题:如何将A请求responseBody中的token传入B请求中的request中 把A请求中的token设置为环境变量,如下: tests["Status code is 200&qu ...

  9. 【Python】tuple and list 练习

    Tuple: 1.       __add__ a = (,,,,,,,,,) b = (,,,,,,,), c = (,,,,), result = a.__add__(b) print(resul ...

  10. HDU3507_Print Article

    这个题目又是一个典型的dp斜率优化的题目.题意是给你n个数,你需要做的是把这个n个数分为连续的若干段,每段的权值为这段数字的和的平方加上M.求最小的总权值. 我们可以根据题意写出朴素版的dp状态转移方 ...