包装-授权 包装 授权

包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)

class List(list):
    #需求:只能向列表里添加str类型的数据
    def append(self, p_object):     #自己定义一个list的append方法,并添加操作

        #这种方式可以做判断
        # if type(p_object) is str:   #只能加入str类型到list
        #     # self.append(p_object) #进入无限递归
        #     #可以掉他爹的方法list.append(self,p_object)  这样也可以加入
        #     #list.append(self, p_object)
        #     super().append(p_object)    #super代表实例父类也就是list,不用传self了
        # else:
        #     print('只有字符串类型能被添加到列表中')

        #也可以通过isinstance()函数判断,isinstance(a,b) 判断a实例是不是由b类产生的
        if not isinstance(p_object,str):
            print('只有字符串类型能被添加到列表中')
            return
        # self.append(p_object) #进入无限递归
        super().append(p_object)

    # 自己练习,需求在insert加入对象时,判断类型,为str才允许加入
    def insert(self, obj_index, type_obj):
        if type(type_obj) is str:
            list.insert(self, obj_index, type_obj)
            print('你添加的[%s]加入成功,加入到位置[%s]' % (type_obj, obj_index))
        else:
            print('你添加的[%s]不是str类型,不允许添加' % type_obj)


    #自己根据需求,继承类并新增自己的需求方法
    def show_mid(self):
        '我新增的方法'
        index=int(len(self)/2)      #根据索引取中间的值
        print(self[index])

l1=List('hello')    #相当于实例化一个对象

l1.append('abc')   #通过实例化对象,调用自己重写的append方法
print(l1,type(l1))  #打印l1列表,可以看到abc已经加入到列表里了
                    #执行结果:['h', 'e', 'l', 'l', 'o', 'abc'] <class '__main__.List'>
print(l1.__dict__)    #但是在实例和类的属性字典里并没有存在,因为没有往里边真正的添加值,只是添加到l1列表内
                        #执行结果:{}
l1=List('hello')
l1.insert(1,'zhaok')

#数字无法添加成功
l1.append(1)    #类型判断不通过,不添加
print('-->',l1) #执行结果:只有字符串类型能被添加到列表中,--> ['h', 'zhaok', 'e', 'l', 'l', 'o']

#基于标准类型新增了功能
l1.show_mid()

授权

授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。

实现授权的关键点就是覆盖__getattr__方法

class FileHand:
    def __init__(self,filename,model='r',encoding='utf-8'):
        self.file_had = open(filename,model,encoding='utf-8')   #把open所有的功能都授权给一个实例对象

    def __getattr__(self, item):    #当用户实例化过后去调用自己和类不存在的方法时,会触发__getattr__运行
        print(self,item)            #self得到就是自己本身f1,item调用的方法名
        return getattr(self.file_had,item)  #getattr(obj,'属性') 得到obj里的'属性'信息
                                            #实例自己字典中file_had包含着open的所有方法,找到真正的open方法并返回给调用者

f1 = FileHand('a.txt','r+','utf-8')  #实例化对象
print(f1.read())    #f1.read 自己的属性字典里没有,找类,类中也没有,触发__getattr__
                    #经过__getattr__的操作,返回得到了真正的open的read方法,可以执行成功
f1.write('可以写了
')  #open的所有方法,f1都可以执行。如:read,seek等等
import time
class FileHandle:
    def __init__(self,filename,mode='r',encoding='utf-8'):
        self.file=open(filename,mode,encoding=encoding)
  
  #拿到self.file,可以对真正的open方法进行重写,添加些功能
  #每次写文件时,文件前都要加入时间
  def write(self,line): t=time.strftime('%Y-%m-%d %T') self.file.write('%s %s' %(t,line)) def __getattr__(self, item): return getattr(self.file,item) f1=FileHandle('b.txt','w+') f1.write('你好啊') f1.seek(0) print(f1.read()) f1.close()
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
#我们来加上b模式支持
import time
class FileHandle:
    def __init__(self,filename,mode='r',encoding='utf-8'):
        if 'b' in mode:
            self.file=open(filename,mode)
        else:
            self.file=open(filename,mode,encoding=encoding)
        self.encoding=encoding

    def write(self,line):
        t=time.strftime('%Y-%m-%d %T')
        if 'b' in self.mode:
            msg=bytes('%s %s' %(t,line),encoding=self.encoding)
        self.file.write(msg)

    def __getattr__(self, item):
        return getattr(self.file,item)

f1=FileHandle('b.txt','wb')
f1.write('你好啊啊啊啊啊') #自定制的write,不用在进行encode转成二进制去写了,简单,大气
f1.close()