包装在Python中经常用到,包装就是把已存在的程序重新打包,使这个程序更加适合当前应用环境。而授权是包装特有的一个属性,通过授权,可以使当前类调用传入对象已存在的属性。
1. 包装
包装就是对已存在对象的属性功能进行调整,删除不需要的、添加或是修改已存在的功能,以达到自己所理想的规格,并装换成另外一种更适合当前使用场合的对外接口。包装包括定义一个类,它的实例拥有标准类型的核心行为。
例如,我们需要处理一个数据,处理这个数据需要一系列的步骤,我们可以将这些步骤写到一个类里面。每当应用于不同的场景时,就将各种适合于此场景的方法包装成类,且原对象的属性和方法依然可以调用。
或许我们会觉得通过继承的方式可以达到这个目的,将父类中的成员全部继承,然后再对方法进行覆盖重写,还可以添加自己想要的属性和方法。但是在 Python2.2之前,基本数据类型不属于类,这样基本数据类型就不能被继承,也不能进行包装。
以下是包装实例:
class Wrap(object):
def __init__(self,obj): # 声明了构造函数,模拟要包装对象的构造方法
self.__obj = obj # __obj就是这个被包装对象的核心
def get(self): # 获取__obj对象
return self.__obj
def __repr__(self):
return 'self.__obj'
def __str__(self): # 转换__obj对象
return str(self.__obj)
def __getattr__(self,thelist):
return getattr(self.__obj,thelist)
2. 授权
授权是包装的一个特性,采用已存在的功能达到最大限度的代码重用。在包装中我们可以新建、修改或删除已有的功能,授权的过程就是将更新的功能交由新类来处理,已存在的功能就授权给对象的默认属性。
要实现授权,一定要覆盖__getattr__()方法。在代码里包含一个对getattr()内建函数的调用,**调用getattr()**得到默认对象的属性(数据属性或者方法)并返回它,以便于访问或者调用。
当引用一个属性时,解释器首先会在局部名称空间中查找那个名字,比如一个自定义的方法或局部实例属性。如果没有在局部字典中找到,则搜索类名称空间,以防一个类属性被访问。最后,如果两类搜索都失败了,搜索则对原对象开始授权请求,此时__getattr__()会被调用。
对象销毁也称垃圾回收,很多语言都有自己的垃圾回收机制。Python 的垃圾回收机制使用了引用计数这一机制来追踪内存中的对象。
3. 增加引用计数
在 Python 中,当一个对象被创建时,就自动地创建了一个引用计数器。当引用计数加1时,增加对这个对象的引用,引用计数器也依次增加。
例如:
x = 12
y = x
z = y
在这个例子中,语句x = 12创建了对象12并将这个对象赋值给了x。此时12的引用计数为1,语句y = x创建了一个指向对象12的别名y,计数为2,在语句z = y中又创建了一个别名,所以此时对象12的引用计数为3。
对象的引用计数在下列情况下增加:
- 对象被创建时;
- 创建了另一个别名时;
- 被作为参数传递给函数时;
- 成为容器对象的一个元素时。
4. 减少引用计数
当别名被重新赋值时,源对象的引用计数减1。
例如:
var1 = "we"
var2 = var1
var1 = 12
在这个例子中,对象"we"赋值给了var1,引用为1,语句var2 = var1将对象的值又赋给了var2,引用为2。但在语句var1 = 12中,将对象12赋值给了var1,此时对象"we"的引用减1,12的引用加1。
对象的引用计数在下列情况下减少:
- 一个本地引用离开了其作用范围时,比如函数结束;
- 对象别名被销毁时;
- 对象本身被销毁时。
5. 对象销毁
当对象的引用计数变为0时,它被垃圾回收。Python 中的垃圾回收机制可以处理两种情况,一种是引用为0,另一种是循环引用。循环引用是指两个对象互相引用,且都没有外部的对象对它们进行引用。
例如:
class delObject:
def __init__(self):
self.var = 100
def __del__(self):
class_name = self.__class__.__name__
print("对象%s销毁" %class_name)
do1 = delObject()
do2 = do1
do3 = do1
print(id(do1))
print(id(do2))
print(id(do3))
del(do1)
del(do2)
del(do3)
结果为:
2176419869752
2176419869752
2176419869752
对象delObject销毁
在这个例子中,del()为一个析构函数。当删除对象时,会调用本身的函数,在对象删除完毕时也会再次调用这个函数。